2015-08-14 12 views
5

Abbiamo appena iniziato a imparare la meta programmazione dei modelli in C++ 11. Come esercizio abbiamo scritto un programma che emette la rappresentazione binaria di un valore int. Abbiamo pensato a due possibili implementazioni. Il primo utilizza la ricorsione con valori enum mentre il secondo metodo utilizza una funzione constexpr.Metaprogrammazione con constexpr o struct

La nostra aspettativa era che entrambe le implementazioni risultassero in eseguibili della stessa dimensione. Tuttavia, la prima implementazione porta a 9064 byte mentre la seconda ha 9096 byte. Non ci importa la piccola differenza in byte, ma non capiamo cosa causa la differenza.

Abbiamo compilato il programma con GCC 4.8.2 senza flag di ottimizzazione, tuttavia, gli stessi risultati si trovano il flag -O2.

#include <iostream> 
using namespace std; 

template <int val> 
struct Bin 
{ 
    enum { value = 10 * Bin<(val >> 1)>::value + (val & 1) }; 
}; 

template <> 
struct Bin<0> 
{ 
    enum { value = 0 }; 
}; 

constexpr int bin(int val) 
{ 
    return val == 0 ? 0 : (10 * bin(val >> 1) + (val & 1)); 
} 


int main() 
{ 
    // Option 1 
    cout << Bin<5>::value << '\n' 
     << Bin<27>::value << '\n'; 

    // Option 2 
    cout << bin(5) << '\n' 
     << bin(27) << '\n'; 
} 
+0

Questo programma sembra abbastanza semplice da smontare e analizzare. – Borsunho

+4

Le funzioni 'constexpr' non sono garantite per essere valutate in fase di compilazione a meno che non vengano utilizzate in un contesto che richiede un'espressione costante. –

risposta

3

constexpr funzioni possono essere valutato al momento della compilazione. Non sono tenuti a

Per il codice fornito, il compilatore non sta effettivamente effettuando tale operazione e bin viene richiamato in fase di esecuzione; questo significa che la funzione non può essere gettata via dall'assemblea. Richiedendo esplicitamente i valori da constexpr con

constexpr auto i = bin(5), j = bin(27); 

le chiamate a bin sono fatte al momento della compilazione, come illustrato here. Con

cout << bin(5) << '\n' 
     << bin(27) << '\n'; 

il codice emesso rilevante è

movl $5, %edi # Parameter 
callq bin(int) # Here's the call to bin 
movl std::cout, %edi 
movl %eax, %esi 
callq std::basic_ostream<char, std::char_traits<char> >::operator<<(int) 
[...] 
movl $27, %edi # parameter 
callq bin(int) # call to bin 
movq %rbx, %rdi 
movl %eax, %esi 
callq std::basic_ostream<char, std::char_traits<char> >::operator<<(int) 

Quando la chiamata viene eliso, la dimensione è la stessa per entrambe le versioni.

+0

Grazie per la risposta. C'è un modo per richiedere esplicitamente che i valori siano 'constexpr' senza memorizzarli in una variabile? – Michiel

+0

@MichielUitHetBroek I metodi disponibili per forzare le funzioni di 'constexpr' da valutare in fase di compilazione richiedono un'ulteriore codifica (spesso ottimizzata) e il più semplice è l'utilizzo di un valore in fase di compilazione. Vedi [questo] (https://stackoverflow.com/questions/14248235/when-does-a-constexpr-function-get-evaluated-at-compile-time?rq=1) e correlati. – edmz

Problemi correlati