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

У меня есть функция шаблона, в которой тип перечисления преобразуется в его базовый тип, который отлично работает, но я написал перегрузку, которая должна принимать целое число и возвращаться сама, и это дает мне ошибку, что 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;
 }
</tt></tt></std::is_enum<tt></typename></typename>

Demo

2 ответа

std::underlying_type<tt>::type</tt> оценивается в std::enable_if, хотя std::is_enum<tt>::value</tt> есть 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;
}
</tt></tt></typename></typename>

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


При попытке создать экземпляр std::underlying_type с 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.
</class>

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

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;
}
</tt></tt></std::is_enum<tt></typename></typename>

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

DEMO

licensed under cc by-sa 3.0 with attribution.