2013-08-20 15 views
10

Sto sperimentando nuove funzionalità del C++ 11, soprattutto in constexpr. Se voglio codificare un pow con il modello mi limiterò a fare:constexpr versus template, pow function

//pow 
template<class T, std::size_t n> 
struct helper_pow{ 
    inline static T pow(T const& a){ 
     return a*helper_pow<T,n-1>::pow(a); 
    } 
}; 

//final specialization pow 
template<class T> 
struct helper_pow<T,0>{ 
    inline static T pow(T const& a){ 
     return 1; 
    } 
}; 

Ora, se io chiamo la mia funzione nel mio codice semplicemente:

pow<double,5>(a) // where a is double 

il gruppo corrispondente verrà (gcc 4.8. 0, -O2):

movapd %xmm0, %xmm1 
    movsd %xmm0, 24(%rsp) 
    mulsd %xmm0, %xmm1 
    movq %rbx, %rdi 
    mulsd %xmm0, %xmm1 
    mulsd %xmm0, %xmm1 
    mulsd %xmm0, %xmm1 

Fine il codice è in linea.

Se so che sto cercando la versione constexpr, ho

template <class T> 
inline constexpr T pow(T const& x, std::size_t n){ 
    return n>0 ? x*pow(x,n-1):1; 
} 

Il gruppo corrispondente è ora:

movsd 24(%rsp), %xmm2 
    leaq 24(%rsp), %rdi 
    movl $4, %esi 
    movsd %xmm2, 8(%rsp) 
    call __Z3powIdET_RS0_m 

dove la funzione __Z # powIdET_RS0_m sembra definire con

LCFI1: 
    mulsd %xmm1, %xmm0 
    movapd %xmm0, %xmm2 
    mulsd %xmm1, %xmm2 
    mulsd %xmm2, %xmm1 
    movapd %xmm1, %xmm0 
    ret 

Quindi hai qualche idea sul perché con constexpr la funzione non è in linea e considera come "un esterno " funzione ? Esiste un modo per forzare la linea di una funzione di constexpr? Il migliore.

+1

Perché l'argomento per constexpr 'pow' non è const? –

+0

Se interpreto correttamente lo smontaggio del mio g ++ 4.8.1 ('-O2'), * esegue * inline (e srotola la ricorsione di) il tuo' pow' per piccoli esponenti, se l'esponente è un letterale (noto alla compilazione -tempo dovrebbe essere sufficiente). Per gli esponenti più grandi (ad esempio 10), introduce una funzione. A '-O3', è in linea anche per i maggiori esponenti (14). – dyp

+0

Sebastian: Dimentico^_ ^, DyP: interessante, proverò una nuova versione del compilatore –

risposta

1

inline non è altro che un suggerimento per il compilatore. Può fare tutto ciò che preferisce. Esiste roba specifica del compilatore come pragmas e __declspec per forzare on o off l'inlining su una funzione.

Può essere il riferimento non costante del numero di versione di constexpr. Dovresti comunque passare di valore ad un pow in ogni caso.

1

Non è un errore per una particolare istanziazione di un modello di funzione constexpr non essere realmente constexpr, purché non si tenti di utilizzarlo in un contesto che richiede un'espressione costante. Forse il tuo template istanziato non è constexpr.

Per scoprire, fare questo:

constexpr double powtest = pow(2.0, 5); 

Se il compilatore si lamenta, sapete che c'è qualcosa che non va.

+0

Giusto, conosco questa funzione. Beh, stavo cercando di cambiare la mia implementazione attuale con template, da constexpr ma con un parametro "dinamico" –

+3

Ah, quindi fondamentalmente sei preoccupato che il compilatore abbia allineato la vecchia versione e non incorpori il nuovo. Questo è davvero interessante, specialmente perché sembra che parzialmente si specializzi la funzione di constexpr. –

+0

sì esattamente, il inline rimuove un sacco di gestione dello stack. Dovrei leggere attentamente la norma, e magari postare una domanda sul forum GCC sulla funzione. –