模板 class 构造函数定义 enable_if 在 class 原型之外

template class constructor definition with enable_if outside class prototype

有一个问题与我之前的问题有点相关,它涉及模板 class,它在 class 原型中声明的方法上使用了 std::enable_if,但是实际实施是在外面完成的。

来源:

我想做类似的事情,但是使用 class 构造函数,我想用 std::enable_if 元函数定义外部模板 class。

template <typename T>
using EnableIfArithmetic = typename std::enable_if<std::is_arithmetic<T>::value, void>::type;

template <typename NumericType>
class SomeClass {
public:
    // constructor definition
    template <typename = EnableIfArithmetic<NumericType>>
    SomeClass() {
        // do some stuff
    }
};

所需形式:

template <typename NumericType>
class SomeClass {
public:
     // constructor declaration
     template <typename = EnableIfArithmetic<NumericType>>
     SomeClass();
};

// constructor definition
template <typename NumericType>
template <typename = EnableIfArithmetic<NumericType>>
SomeClass<NumericType>::SomeClass() {
        // constructor implementation
}

但我做对了,没有编译错误。我究竟做错了什么?

模板参数的默认值不应在定义中重复。例如:

template<typename N>
struct S {
    template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
    S(T);
};

template<typename N>
template<typename T, typename>
S<N>::S(T) { }

您使用 SFINAE 的方式不正确:EnableIfArithmetic 应该取决于某些推导类型(在同一模板中)。请参考。例如:

template<typename T = N, typename = EnableIfArithmetic<T>>
S() { }

否则会发生硬故障:

error: no type named 'type' in 'struct std::enable_if'

如果要禁用某些类型的默认构造函数N,您还可以在构造函数内部使用static_assert。但是,它不会对 SFINAE 友好。

template<typename N>
struct S1 {
public:
    template<typename T = N, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
    S1() { }
};

template<typename N>
struct S2 {
public:
    S2() { static_assert(std::is_arithmetic_v<N>); }
};

static_assert(std::is_default_constructible_v<S1<int>>);
static_assert(!std::is_default_constructible_v<S1<void>>);

static_assert(std::is_default_constructible_v<S2<int>>);
static_assert(std::is_default_constructible_v<S2<void>>);