Вопрос по templates, constexpr, c++, static-assert, c++11 – Как проверить, является ли параметр шаблона степенью двойки?

15

Я хочу создать структуру, которая статически выделяет массив2^N bytes, но я не хочу, чтобы пользователи этой структуры указывали этот размер в качестве показателя степени. Пример:

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

Как проверить, является ли этот параметр шаблона степенью двойкиand предупредить пользователя с хорошим сообщением об этом?

Я смог проверить это с помощью простого шаблона:

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

Однако я не могу предупредить пользователя об этом с помощью вменяемого сообщения. Есть идеи?

EDIT

Исправлен неоднозначный пример.

EDIT

1 - это сила двух. Исправлено! :)

EDIT

Используя BOOST_STATIC_ASSERT, я получаю эту ошибку компиляции для этого кода с GCC:

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

ошибка

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

http://ideone.com/cMfEf

EDIT

О, я понял. Это было сообщение, которое я должен был получить, когда утверждение не удалось. Но это не дает пользователю какое-то вменяемое сообщение. :(

Это подразумевается как пример показателя в качестве параметра. 2 ^ 8 = 256 jrok
8 - это степень 2 ... Oliver Charlesworth
& GT;my_stupid_array<char, 8> a2; // And not this... почему не это? triclosan
@jrok: я понимаю, но суть остается ... Oliver Charlesworth
@ triclosan Это может быть так, но это не интуитивно понятно, и, поскольку я не спешу, я подумал, что могу спросить и узнать что-то новое. :) ivarec

Ваш Ответ

3   ответа
16

constexpr инемного тредлинг хаки ты можешь просто

constexpr bool is_powerof2(int v) {
    return v && ((v & (v - 1)) == 0);
}
Это реальное решение.
21

раскомментируйте BOOST_STATIC_ASSERT для 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";
}

Идеальный вывод для C ++ 11

Идеальный вывод для C ++ 03

UPDATE1: другая идея (я знаю, что вы этого не хотите, но для крупных экспонентов это намного проще):

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: на основе комментариев @sehe в чате, вы можете сделать это дляconstexpr функции также

constexpr bool is_power_of_two(int x)
{
    return x && ((x & (x-1)) == 0);
}
Что вы всегда можете сделать сBOOST_STATIC_ASSERT Чтобы включить сообщение это:BOOST_STATIC_ASSERT(val && "This is SO wrong!"), (Для тех, кто задается вопросом: строковый литерал в логическом контексте оценивает указатель на литерал, который всегда ненулевой, т. Е. True)
Черт. Собирался датьthis link, Я должен научиться печатать быстрее.
Ударь меня к этому. Можно также упомянуть BOOST_STATIC_ASSERT для C ++ 03.
BOOST_STATIC_ASSERT принимает только один параметр. Кроме того, я получаю ошибку компиляции, которую я пытаюсь выяснить. Собираюсь обновить вопрос. ivarec
Мой встроенный компилятор пока не работает на C ++ 11. Я попробую альтернативу повышения и добавлю это к ответу, если это сработает. ivarec
11

static_assert предоставить сообщение об ошибке:

template<int N>
struct is_power_of_two {
    static_assert((N > 1) & !(N & (N - 1)), "Template parameter must be a power of two.");
};
N & gt; 1 должно быть N & gt; 0, поскольку 1 равно 2 ^ 0.
+1 Еще немного хулиганских взломов здесь:graphics.stanford.edu/~seander/…, Выложил свою версию на основеconstexpr :/

Похожие вопросы