问题
I want to create a structure that allocates statically an array of 2^N bytes, but I don't want the users of this structure to specify this size as the exponent. Example:
my_stupid_array<char, 32> a1; // I want this!
my_stupid_array<char, 5> a2; // And not this...
How do I check if this template parameter is a power of two and warn the user with a nice message about this?
I've been able to check for this with a simple template:
template<int N>
struct is_power_of_two {
enum {val = (N >= 1) & !(N & (N - 1))};
};
However, I'm unable to warn the user about this with a sane message. Any ideas?
EDIT
Fixed the ambiguous example.
EDIT
1 is a power of two indeed. Fixed that! :)
EDIT
Using BOOST_STATIC_ASSERT, I'm getting this compile error for this code with GCC:
template<int N>
struct is_power_of_two {
enum {val = (N >= 1) & !(N & (N - 1))};
BOOST_STATIC_ASSERT(val);
};
Error
..\main.cpp:29:1: error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'
http://ideone.com/cMfEf
EDIT
Oh, I get it. That was the message that I'm supposed to get when the assert fails. But that fails to give the user some sane message. :(
回答1:
These days, with constexpr
and the bit twiddling hacks you can just
constexpr bool is_powerof2(int v) {
return v && ((v & (v - 1)) == 0);
}
回答2:
static_assert to the rescue (C++11 only, uncomment BOOST_STATIC_ASSERT for 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: other idea (I know you don't want this, but it is a lot easier for large exponents):
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: based on comments by @sehe in the chat, you can do this for constexpr
functions as well
constexpr bool is_power_of_two(int x)
{
return x && ((x & (x-1)) == 0);
}
回答3:
You can use static_assert
to provide an error message:
template<int N>
struct is_power_of_two {
static_assert((N > 1) & !(N & (N - 1)), "Template parameter must be a power of two.");
};
来源:https://stackoverflow.com/questions/10585450/how-do-i-check-if-a-template-parameter-is-a-power-of-two