2011-09-06 10 views
40

Quando si esegue la metaprogrammazione con i modelli C++, esiste un metodo che può essere utilizzato, un po 'come un debugger, per esaminare il modo in cui i modelli vengono istanziati e rispettati? Sembra proprio ora che, quando si crea una complicata rete di modelli, non ci sia davvero un ottimo modo per eseguire il debugging, se non guardando i messaggi di errore del compilatore per vedere come vengono istanziati i template (se ci sono errori del compilatore), e il tentativo di lavorare all'indietro dai messaggi di errore se viene generato qualcosa di inaspettato. Non sono sicuro se quello che sto cercando esista, come dovrebbe essere qualcosa che viene fatto in fase di compilazione, ma fondamentalmente sarebbe un metodo, un po 'come passare il codice ed esaminare lo stack frame in gdb in fase di esecuzione, in cui è possibile arrestare il compilatore e esaminare l'ambiente per la sequenza mediante la quale viene creato un modello o un set di modelli nidificati.Debug delle istanze del modello

Per esempio, diciamo che ho creato un po 'di semplice codice come il seguente:

template<typename T, typename R = void> 
struct int_return_type {}; 

template<typename R> 
struct int_return_type<int, R> 
{ 
    typedef R type; 
}; 

template<typename T, typename R = void> 
struct float_return_type {}; 

template<typename R> 
struct float_return_type<float, R> 
{ 
    typedef R type; 
}; 

template<typename T> 
typename int_return_type<T>::type test() 
{ 
    cout << "T type is int" << endl; 
} 

template<typename T> 
typename float_return_type<T>::type test() 
{ 
    cout << "T type is float" << endl; 
} 

int main() 
{ 
    test<int>(); 
    test<float>(); 
    return 0; 
} 

So che questo è relativamente facile codice da seguire, ma i modelli possono ottenere un po' più coinvolti, soprattutto quando si fa metaprogrammazione, ricorsione, ecc. Capisco che il compilatore invierà messaggi di errore che possono essere utilizzati per dedurre come i modelli vengono istanziati, ma mi chiedo anche cosa può essere fatto quando il codice del template è corretto in senso sintattico, ma il tempo di esecuzione i risultati sono ancora errati. Sarebbe bello, per esempio, avere un metodo per fermare il compilatore e vedere cosa test, come int_return_type e float_return_type, con cui veniva istanziato o quali istanze non funzionavano.

Sono le uniche opzioni disponibili al momento per il debug dei modelli con questo livello di granularità 1) i messaggi di errore del compilatore quando il codice non è corretto, e 2) una combinazione di disassemblatori e debugger per vedere quale codice istanziato è stato generato se l'esecuzione -tempo i risultati non sono corretti? O ci sono altre utility che aiutano a "guardare" come vengono istanziati i template, e vedere/ispezionare quale codice viene generato dal compilatore per investigare ed eseguire il debug degli errori del template?

+3

diverso da 'static_assert' per fare cose che si desidera guardare in errori Non credo che ci sia nulla da aiutare – Flexo

risposta

26

Queste sono piuttosto semplici, ma hanno funzionato per me nella maggior parte dei casi. Sono interessato a vedere anche quello che gli altri hanno da dire.

Scuse per gli esempi inventati.

Utilizzare sandbox

partire con piccoli sandbox a prova di codice del template, non appena si inizia a comportarsi strano o si sta facendo qualcosa di complicato. Sono piuttosto a mio agio con i modelli e lo faccio ancora quasi immediatamente. Semplicemente, scopre gli errori più velocemente. L'hai fatto per noi qui, quindi presumo che questo sia discutibile.

specificare i tipi di temporanee

Temporaries può offuscare in cui le vostre intenzioni non sono soddisfatte. Ho visto un sacco di codice che fa qualcosa di simile al seguito.

template<typename T> 
    T calc(const T &val) { 
    return some_other_calc(val)/100.0; 
    } 

lo dice al compilatore che tipo che ci si aspetta non riuscirà più veloce e potenzialmente vi darà un messaggio migliore per affrontare.

template<typename T> 
    T calc(const T &val) { 
    T val_ = some_other_calc(val); 
    return val_/100.0; 
    } 

Usa TypeId

Utilizzando typeid(T).name() per stampare i nomi dei modelli di istruzioni di debug. Questo ti darà una stringa che puoi usare per vedere come il compilatore ha deciso di soddisfare il tipo.

template<typename T> 
    typename void test() { 
    std::cout << "testing type " << typeid(T).name() << std::endl; 
    // ... 
    } 

evitare inutili implementazioni di default

modelli scrivere in un modo che non si hanno implementazioni predefinite.

template<typename T, bool is_integral = boost::is_numeric<T>::value > 
    struct my_traits; 

template<typename T> 
    struct my_traits<T, true> { 
    typedef uint32_t cast_type; 
    }; 

template<typename T> 
    void print_whole_number(T &val) { 
    std::cout << static_cast<my_traits<T>::cast_type>(val) << std::endl; 
    } 

Questo impone agli utenti di print_whole_number hanno il loro my_traits specializzazione. Otterranno un errore del compilatore invece di metà che funziona perché non è possibile fornire una buona implementazione per tutti i tipi. L'errore del compilatore non sarà immediatamente utile se usato in una parte disparata di una base di codice, ammettiamolo.

+9

+1 * Scrivi modelli in modo che non abbiano implementazioni predefinite * – Manu343726

3

Mi piace usare l'eccellente compilatore Comeau basato su Web per il debug. Può notare errori in termini di compilation standard in cui gli altri compilatori non possono ...

Comeau ha il grande vantaggio di fornire messaggi di errore molto più leggibili rispetto a GCC o MSVC.

Inoltre, ricorda di utilizzare static_assert ovunque, dove possibile, anche se sei sicuro che la risposta sia vera.

+0

BTW, so che questo è un po 'fuori tema, ma sono curioso, il mio esempio di codice sembra essere [compilando bene] (http://ideone.com/zcLmt), altrimenti non l'avrei postato (non c'è niente come postare codice che non verrà compilato) ... quali sono le impostazioni del compilatore Comeau usando? – Jason

+0

@Jason, modalità rigorosa con estensioni C++ 0x. –

+0

@Jason, oh stupido, non ho incollato l'intero codice ^^ –

Problemi correlati