2012-05-14 4 views
15

Voglio creare una struttura che assegna staticamente una serie di 2^N byte, ma non voglio che gli utenti di questa struttura specificino questa dimensione come esponente. Esempio:Come faccio a verificare se un parametro template è una potenza di due?

my_stupid_array<char, 32> a1; // I want this! 
my_stupid_array<char, 5> a2; // And not this... 

Come si controlla se questo parametro modello è una potenza di due e avvertire l'utente con un bel messaggio di questo?

Sono stato in grado di verificare la presenza di questo con un semplice modello:

template<int N> 
struct is_power_of_two { 
    enum {val = (N >= 1) & !(N & (N - 1))}; 
}; 

Tuttavia, sono in grado di avvertire l'utente di questo con un messaggio sano. Qualche idea?

EDIT

fissa l'esempio ambiguo.

EDIT

1 è una potenza di due effetti. Risolto il problema! :)

EDIT

Utilizzando BOOST_STATIC_ASSERT, sto ottenendo questo errore di compilazione per questo codice con GCC:

template<int N> 
struct is_power_of_two { 
    enum {val = (N >= 1) & !(N & (N - 1))}; 
    BOOST_STATIC_ASSERT(val); 
}; 

errore

..\main.cpp:29:1: error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>' 

http://ideone.com/cMfEf

EDIT

Oh, ho capito. Quello era il messaggio che dovrei ottenere quando l'asserzione fallisce. Ma questo non riesce a dare all'utente un messaggio sensato.:(

+6

8 è una potenza di 2 ... –

+0

È inteso come un esempio di esponente come parametro. 2^8 = 256 – jrok

+0

> 'my_stupid_array a2; // E non questo ... 'perché non questo? – triclosan

risposta

14

In questi giorni, con constexpr e bit twiddling hacks è possibile solo

constexpr bool is_powerof2(int v) { 
    return v && ((v & (v - 1)) == 0); 
} 
+0

Questa è la vera soluzione. – plasmacel

21

static_assert alla riscossa (C++ 11 solo, BOOST_STATIC_ASSERT rimuovere il commento per C++ 03):

#include<iostream> 
// #include <boost/static_assert.hpp> 

template<int N> 
struct is_power_of_two { 
    enum {val = N && !(N & (N - 1))}; 
    static_assert(val, "should use a power of 2 as template parameter"); 
    // BOOST_STATIC_ASSERT(val); // without C++11 support, won't take a string message 
}; 

int main() 
{ 
     std::cout << is_power_of_two<2>::val << "\n"; 
     std::cout << is_power_of_two<3>::val << "\n"; 
} 

Ideone output for C++11

Ideone output for C++03

Update1: altra idea (So che non lo vuoi, ma è molto più semplice per i grandi esponenti):

template<int N> 
make_power_of_two 
{ 
    enum { val = 1 << N }; 
}; 

my_stupid_array<char, make_power_of_two<5>::val > a1; // size 2^5 = 32 

UPDATE2: sulla base di commenti @sehe nella chat, si può fare questo per constexpr funzioni così

constexpr bool is_power_of_two(int x) 
{ 
    return x && ((x & (x-1)) == 0); 
} 
+1

Mi picchia. Tanto vale citare BOOST_STATIC_ASSERT per C++ 03. – jrok

+0

Dannazione. Stavo per dare [questo link] (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_staticassert.html). Devo imparare a digitare più velocemente. –

+1

Il mio compilatore incorporato non farà ancora C++ 11. Proverò l'alternativa boost e aggiungerò alla risposta se funziona. – ivarec

9

È possibile utilizzare static_assert per fornire un messaggio di errore:

template<int N> 
struct is_power_of_two { 
    static_assert((N > 1) & !(N & (N - 1)), "Template parameter must be a power of two."); 
}; 
+0

+1 Altri tipi di hack che girano i bit qui: http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2.Ho pubblicato la mia versione basata su 'constexpr':/ – sehe