2012-05-14 3 views
15

Ich möchte eine Struktur erstellen, die statisch ein Array von 2^N Bytes zuweist, aber ich möchte nicht, dass die Benutzer dieser Struktur diese Größe als Exponent angeben. Beispiel:Wie überprüfe ich, ob ein Template-Parameter eine Potenz von zwei ist?

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

Wie kann ich überprüfen, ob diese Template-Parameter eine Zweierpotenz ist und warn der Benutzer mit einer schönen Nachricht über diese?

Ich habe in der Lage gewesen, dies mit einer einfachen Vorlage zu überprüfen:

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

Aber ich bin nicht in der Lage die Benutzer über diese mit einer gesunden Nachricht zu warnen. Irgendwelche Ideen?

EDIT

die zweideutige Beispiel behoben.

EDIT

1 ist eine Potenz von zwei in der Tat. Das wurde behoben! :)

EDIT

Mit BOOST_STATIC_ASSERT, erhalte ich diesen Compiler-Fehler für diesen Code mit GCC:

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

Fehler

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

http://ideone.com/cMfEf

EDIT

Oh, ich verstehe. Das war die Nachricht, die ich bekommen sollte, wenn die Assert fehlschlägt. Aber das gibt dem Benutzer keine vernünftige Nachricht.:(

+6

8 ist eine Potenz von 2 ... –

+0

Es ist als Beispiel für den Exponenten als Parameter gedacht. 2^8 = 256 – jrok

+0

> 'my_stupid_array a2; // Und nicht das ... 'warum nicht das? – triclosan

Antwort

14

In diesen Tagen, mit constexpr und der bit twiddling hacks können Sie einfach

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

Dies ist die echte Lösung. – plasmacel

21

static_assert zur Rettung (C 11 ++ nur Kommentar- BOOST_STATIC_ASSERT für 03 C++):

#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: andere Idee (Ich weiß, dass Sie das nicht wollen, aber es ist viel einfacher für große Exponenten):

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: basierend auf Kommentare von @sehe im Chat, können Sie dies auch für constexpr Funktionen tun

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

Beat mich dazu. Könnte auch BOOST_STATIC_ASSERT für C++ 03 erwähnen. – jrok

+0

Verdammt. War gerade dabei, [diesen Link] zu geben (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_staticassert.html). Ich muss lernen, schneller zu tippen. –

+1

Mein eingebetteter Compiler wird C++ 11 noch nicht ausführen. Ich werde die Boost-Alternative versuchen und diese zur Antwort hinzufügen, wenn es funktioniert. – ivarec

9

Sie static_assert eine Fehlermeldung liefern können:

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 Mehr Bit Twiddling Hacks hier: http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2.Posted meine eigene Version basierend auf 'constexpr':/ – sehe