Всегда ли необходимо дублировать параметр шаблона класса при включении конструкторов на его основе?

Вообще при использовании enable_if на основе типа шаблона класса необходимо продублировать тип шаблона класса в качестве параметра шаблона конструктора или метода:

template <
    typename U = T,
    typename = typename std::enable_if<
        !std::is_void<U>::value
    >::type
>
Class() { }

Когда именно это необходимо (или нет)?

Например, следующий код прекрасно компилируется на G++, Clang и VC++...

template <typename T = void>
class Class {
public:
    template <
        typename U,
        typename = typename std::enable_if<
            // Is the use of T here allowed?
            std::is_void<T>::value
            || std::is_base_of<T, U>::value
        >::type
    >
    Class(U &&arg) {
        std::cout << "Derived" << std::endl;
    }

    template <
        typename U,
        typename ...U_Rest,
        typename = typename std::enable_if<
            // Is the use of T here allowed?
            !std::is_void<T>::value
            && !std::is_base_of<T, U>::value
        >::type
    >
    Class(U &&arg, U_Rest &&...rest) {
        std::cout << "Not Derived" << std::endl;
    }
};

Ideone Rextester

... но использует T непосредственно как часть enable_if, В частности, если T является void, версия конструктора "Производная" будет всегда включена, а версия "Не производная" всегда будет отключена, независимо от параметров U,

Действительно ли вышесказанное действительно законно в соответствии со стандартом? Или компиляторы просто принимают это, вероятно, из-за "не требуется никакой диагностики"?

1 ответ

Решение

SFINAE применяется к шаблонному методу, и он не должен быть серьезным сбоем (поэтому в основном должен зависеть от его шаблонных параметров).

Здесь ваше состояние зависит от Uтак что все в порядке.

Обратите внимание, что вы должны предпочесть

template <typename U, std::enable_if_t<cond>* = nullptr>

над

template <typename U, typename = std::enable_if_t<cond>>

разрешить писать отключенную версию

template <typename U, std::enable_if_t<!cond>* = nullptr>

как

template <typename U, typename = std::enable_if_t<cond>> //...
template <typename U, typename = std::enable_if_t<!cond>> // ...

иметь такую ​​же подпись.

Другие вопросы по тегам