2012-05-14 47 views
15

Tôi muốn tạo cấu trúc phân bổ tĩnh một mảng 2^N byte, nhưng tôi không muốn người dùng của cấu trúc này chỉ định kích thước này làm số mũ. Ví dụ:Làm cách nào để kiểm tra xem thông số mẫu có phải là một tham số của hai không?

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

Làm thế nào để kiểm tra xem thông số mẫu này là một sức mạnh của hai cảnh báo người sử dụng với một thông điệp tốt đẹp về điều này?

tôi đã có thể để kiểm tra điều này với một mẫu đơn giản:

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

Tuy nhiên, tôi không thể để cảnh báo người dùng về vấn đề này với một thông điệp lành mạnh. Bất kỳ ý tưởng?

EDIT

cố định ví dụ rõ ràng.

EDIT

1 là một sức mạnh của hai thực sự. Đã sửa lỗi đó! :)

EDIT

Sử dụng BOOST_STATIC_ASSERT, tôi nhận được lỗi biên dịch này cho mã này với GCC:

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

Lỗi

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

http://ideone.com/cMfEf

EDIT

Ồ, tôi hiểu rồi. Đó là thông điệp mà tôi phải nhận được khi khẳng định thất bại. Nhưng điều đó không cung cấp cho người dùng một số thông điệp lành mạnh.:(

+6

8 là công suất của 2 ... –

+0

Nó có nghĩa là một ví dụ về số mũ làm tham số. 2^8 = 256 – jrok

+0

> 'my_stupid_array a2; // Và không phải điều này ... 'tại sao không phải thế này? – triclosan

Trả lời

14

Những ngày này, với constexprbit twiddling hacks bạn chỉ có thể

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

Đây là giải pháp thực sự. – plasmacel

21

static_assert để giải cứu (C++ 11 chỉ, BOOST_STATIC_ASSERT bỏ ghi chú cho 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: ý tưởng khác (Tôi biết bạn không muốn điều này, nhưng nó dễ dàng hơn nhiều đối với những người lớn):

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: dựa trên ý kiến ​​của @sehe đang trong phòng chát, bạn có thể làm điều này cho constexpr chức năng cũng

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

Đánh tôi với nó. Có thể đề cập đến BOOST_STATIC_ASSERT cho C++ 03. – jrok

+0

Damnit. Vừa mới cung cấp cho [liên kết này] (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_staticassert.html). Tôi phải học cách gõ nhanh hơn. –

+1

Trình biên dịch nhúng của tôi sẽ không thực hiện C++ 11. Tôi sẽ thử thay thế tăng cường và thêm điều này vào câu trả lời nếu nó hoạt động. – ivarec

9

Bạn có thể sử dụng static_assert để cung cấp một thông báo lỗi:

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 Thêm nhiều lỗ hổng ở đây: http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2.Đăng phiên bản của riêng tôi dựa trên 'constexpr':/ – sehe

Các vấn đề liên quan