вывод аргумента шаблона с сильно типизированными перечислениями - PullRequest
21 голосов
/ 22 февраля 2012

Если у меня нормальное (слабое) перечисление, я могу использовать его перечисляемые значения в качестве нетиповых параметров шаблона, например, так:

enum { Cat, Dog, Horse };

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

и вызывать его как: magic<Cat>(t)

Насколько я могу видеть, если у меня есть строго типизированное перечисление и я не хочу жестко кодировать тип перечисления, я получаю:

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
    return magical_traits<EnumVal>::invoke(t);
}

и теперь мне нужно написать: magic<Animal, Animal::Cat>(t), что кажется избыточным.

Есть ли способ избежать ввода как класса enum, так и значения, за исключением

#define MAGIC(E, T) (magic<decltype(E), E>(T));

Ответы [ 4 ]

13 голосов
/ 25 ноября 2017

Вы можете сделать это так, если вы можете использовать C ++ 17

#include <type_traits>

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal> 
void magic_impl()
{
    static_assert(std::is_same_v<EnumClass, Animal>);
    static_assert(EnumVal == Animal::Cat);
}

template <auto EnumVal>
void magic()
{
    magic_impl<decltype(EnumVal), EnumVal>();
}

int main()
{
    magic<Animal::Cat>();
}

демо: http://coliru.stacked -crooked.com / а / 9ac5095e8434c9da

13 голосов
/ 22 февраля 2012

Извините, я должен вам сказать, что

Это невозможно

Возьмите макрос, поместите его в страшный заголовок и защитите его от сценария очистки вашего коллеги. Надеюсь на лучшее.

2 голосов
/ 22 февраля 2012

Если вас интересует только значение enum, а не его тип, вы можете использовать функцию constexpr для преобразования значения в целое число, избегая повторения имени типа.

enum class Animal { Cat, Dog, Horse };

template <typename T> constexpr int val(T t)
{
    return static_cast<int>(t);
}

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

magic<val(Animal::Cat)>(t);

Однако, как уже указывали другие, если вы хотите, чтобы это также зависело от типа, оно не будет работать.

0 голосов
/ 25 ноября 2017

На этот вопрос есть принятый ответ (с голосованием).

При рефакторинге собственного кода я нашел более полное решение:

Шаг 1: используя код, который я писал:

template<typename V, typename EnumClass, EnumClass Discriminator>
class strong_type final // type-safe wrapper for input parameters
{
    V value;
public:
    constexpr explicit strong_type(V x): value{x} {}
    constexpr auto get() const { return value; }
};

Шаг 2: код клиента:

enum class color { red, green, blue, alpha };

// the part OP was asking about:
template<color C>
using color_channel = strong_type<std::uint8_t, color, C>;

using red = color_channel<color::red>; // single argument here
using green = color_channel<color::green>;
using blue = color_channel<color::blue>;
using alpha = color_channel<color::alpha>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...