启用基于类模板形参的构造函数时,是否总是需要复制该类模板形参?

Is it always necessary to duplicate a class template parameter when enabling constructors based on it?

本文关键字:形参 复制 是否 于类模 构造函数 启用      更新时间:2023-10-16

通常,当基于类的模板类型使用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的一部分。具体来说,如果Tvoid,则构造函数的"派生"版本将始终被启用,而"非派生"版本将始终被禁用,无论参数U

根据标准,上述内容是否合法?或者编译器只是接受它,可能是由于"不需要诊断"?

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>> // ...