"Конверсия" от типа к тому же типу вызывает ошибку

100
4

У меня есть функция шаблона, в которой тип перечисления преобразуется в его базовый тип, который отлично работает, но я написал перегрузку, которая должна принимать целое число и возвращаться сама, и это дает мне ошибку, что int не является типом перечисления. В моем шаблоне это должно быть отфильтровано. Что не так?


Вот код шаблона:


  template <typename TT>
static constexpr auto get_value(TT t)
-> typename std::enable_if<!std::is_enum<TT>::value, TT>::type
{
return t;
}

template <typename TT>
static constexpr auto get_value(TT t)
-> typename std::enable_if<std::is_enum<TT>::value, typename std::underlying_type<TT>::type>::type
{
return (typename std::underlying_type<TT>::type)t;
}


Demo

спросил(а) 2015-09-08T17:31:00+03:00 4 года, 6 месяцев назад
1
Решение
82

std::underlying_type<TT>::type оценивается в std::enable_if, хотя std::is_enum<TT>::value есть false, поскольку false не является ошибкой. Поскольку оценивается тип не перечисления, он вызывает ошибку. Если мы переместим SFINAE в параметры шаблона, мы получим желаемые перегрузки и вернем правильный тип.


template <typename TT, typename std::enable_if<!std::is_enum<TT>::value, TT>::type* = nullptr>
static constexpr auto get_value(TT t) -> TT
{
return t;
}

template <typename TT, typename std::enable_if<std::is_enum<TT>::value>::type* = nullptr>
static constexpr auto get_value(TT t) -> typename std::underlying_type<TT>::type
{
return (typename std::underlying_type<TT>::type)t;
}

Вы можете увидеть, как он работает в этом Live Example

ответил(а) 2015-09-08T18:19:00+03:00 4 года, 6 месяцев назад
81

При попытке создать экземпляр std::underlying_type<T> с T, который не является типом перечисления, вы нарушаете требование, которое Стандарт накладывает на параметр шаблона T:


§ 20.10.7.6 [meta.trans.other]/Таблица 57:


       Template         |         Condition         |       Comments
------------------------+---------------------------+-----------------------
template <class T> | T shall be an enumeration | The member typedef
struct underlying_type; | type (7.2) | type shall name
| | the underlying type
| | of T.

Здесь альтернативный подход, если вам не нравятся какие-либо дополнительные параметры шаблона:

template <typename TT>
static constexpr auto get_value(TT t)
-> typename std::enable_if<!std::is_enum<TT>::value, TT>::type
{
return t;
}

template <typename TT>
static constexpr auto get_value(TT t)
-> typename std::enable_if<std::is_enum<TT>::value
, std::underlying_type<TT>
>::type::type
{
return (typename std::underlying_type<TT>::type)t;
}


Таким образом, экземпляр std::underlying_type<TT> отложен до тех пор, пока условие в std::enable_if не примет значение true, потому что запрашивается вложенное определение type для возврата std::enable_if<B,T>::type.


DEMO

ответил(а) 2015-09-08T20:54:00+03:00 4 года, 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема