Мне нужна функция, которая преобразует тип From в тип To (To и From являются перечислениями), однако перечисление E1 может быть преобразовано только в E2, мне нужно получить сообщение об ошибке, если пользователь пытается, например, преобразовать E1 в E3.

template<typename From, typename To>
static To map(From f){
    return static_cast<To>(f);
}

Как я могу это сделать? Спасибо!

c++
1
Ionut Cosmin Mihai 15 Апр 2016 в 11:56

4 ответа

Лучший ответ

Одно возможное решение: static_assert

template<typename From, typename To>
static To map(From f) {
    static_assert(!(std::is_same<From, E1>::value && std::is_same<To, E3>::value),
                  "cannot cast from E1 to E3");

    return static_cast<To>(f);
}

auto main() -> int {
    E1 a;
    const auto b = map<E1, E2>(a); // compiles
    const auto c = map<E1, E3>(a); // won't compile

    return 0;
}
2
CppChris 15 Апр 2016 в 09:08

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

template<typename To, typename From>
To map(From f){
    return static_cast<To>(f);
}

template<>
E2 map(E1 f){
    return static_cast<E2>(f);
}

Когда функция map() вызывается с типом E1, тогда специализированная функция шаблона выполняется вместо обычной функции шаблона. Но кроме типа E1 вызывается обычная функция шаблона.

Это заставит пользователя преобразовать E1 только в E2. Если вы хотите вызвать исключение или assert измените определение по своему желанию.

1
jblixr 16 Апр 2016 в 10:19

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

Сначала создайте функцию основного шаблона, но не предоставляйте ее реализацию:

template<typename To, typename From>
To map(From from);

Теперь сделаем специализацию для отображений, которые имеют смысл:

template<>
E2 map(E1 from)
{
    return static_cast<E2>(from);
}

Поскольку вы указали специализацию для сопоставлений, которые имеют смысл, вы получите ошибку, если попытаетесь вызвать те, которые не имеют смысла. Например, на VS2012, если вы это сделаете:

E3 value = map<E3>(e1_value);

Вы получите ошибку «неразрешенный внешний символ», поскольку для сопоставления нет реализации.

0
Sean 15 Апр 2016 в 09:20

Ниже представлено решение с использованием концепций. Насколько мне известно, концепции реализованы только в gcc6, который все еще является экспериментальным.

#include <type_traits>

enum E1{};
enum E2{};
enum E3{};

template <class T, class U> concept bool Same = std::is_same<T,U>::value;

template<typename From, typename To>
static To map(From f)
 requires !(Same<From, E1> && Same<To, E3>)
{
    return static_cast<To>(f);
}

int main()
{
    E1 e1;
    E2 e2;
    E3 e3;

    map<E1, E2>(e1); // Ok
    map<E1, E3>(e1); // Compile Error !
}

Покажет ошибку, как показано ниже:

prog.cc: In function 'int main()':
prog.cc:23:19: error: cannot call function 'To map(From) requires predicate(!((Same<From, E1>) && (Same<To, E3>))) [with From = E1; To = E3]'
     map<E1, E3>(e1);
                   ^
prog.cc:10:11: note:   constraints not satisfied
 static To map(From f)
           ^~~

http://melpon.org/wandbox/permlink/mEG3Rl5jaMXj0GVg

Скомпилирован с экспериментальной версией gcc 6.0:

$ g ++ prog.cc -Wall -Wextra -I / usr / local / boost-1.60.0 / include -std = gnu ++ 1z "-fconcepts"

0
marcinj 15 Апр 2016 в 09:30