C ++ 14 черновик n4140 читает
T
должен быть типом перечисления
за template <class T> struct underlying_type
,
Как плохо это писать
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>
когда T
может быть произвольного типа? Буду ли я переходить на UB и удалит ли компилятор мой $ HOME (потому что юристы говорят, что «под UB может случиться что угодно»)?
Я ступлю на UB […]
Технически да. Но практически он просто не скомпилируется для типов без перечисления. Когда вы пишете:
std::conditional_t<std::is_enum<T>::value, std::underlying_type_t<T>, foo>;
^^^^^^^^^^^^^^^^^^^^^^^^^
Этот параметр шаблона должен быть оценен до conditional
шаблон может быть создан. Это эквивалентно всем аргументам функции, которые должны быть вызваны до начала тела функции. Для не перечислимых типов underlying_type<T>
является неполным (уверен, что он указан как неопределенный в стандарте, но давайте будем разумным), поэтому нет underlying_type_t
, Таким образом, создание экземпляров не удается.
Что вам нужно сделать, это задержка экземпляр в этом случае:
template <class T> struct tag { using type = T; };
typename std::conditional_t<
std::is_enum<T>::value,
std::underlying_type<T>,
tag<foo>>::type;
Теперь наш conditional
вместо выбора типов выбирается метафункция! underlying_type<T>::type
будет создан только для T
быть перечислением. Мы дополнительно должны обернуть foo
превратить это в метафункцию.
Это распространенный шаблон, который был особенным в Boost.MPL и называется eval_if
, который будет выглядеть так:
template <bool B, class T, class F>
using eval_if_t = typename std::conditional_t<B, T, F>::type;
Обратите внимание, что мы оба используем conditional_t
а также ::type
,
Других решений пока нет …