метапрограммирование — Какова стратегия оценки (нетерпеливый, ленивый, …) метафункций C ++, таких как std :: conditional?

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 может случиться что угодно»)?

1

Решение

Я ступлю на 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,

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]