SFINAE构造函数

时间:2018-07-11 19:04:29

标签: c++ sfinae

我一直喜欢这样的SFINAE语法作为函数,看起来通常运行良好!

template <class Integer, class = typename std::enable_if<std::is_integral<Integer>::value>::type>
T(Integer n) {
    // ...
}

但是在同一堂课上我也想这样做时遇到了一个问题...

template <class Float, class = typename std::enable_if<std::is_floating_point<Float>::value>::type>
T(Float n) {
    // ...
}

出现这样的错误:

./../T.h:286:2: error: constructor cannot be redeclared
        T(Float n) {
        ^
./../T.h:281:2: note: previous definition is here
        T(Integer n) {
        ^
1 error generated.

这些构造函数不是只为适当的类型存在而不会同时存在吗?他们为什么会冲突?

我在这里有点厚吗?

另一方面,它确实可以工作(但是我不太喜欢语法):

template <class Integer>
T(Integer n, typename std::enable_if<std::is_integral<Integer>::value>::type* = nullptr) {
}

template <class Float>
T(Float n, typename std::enable_if<std::is_floating_point<Float>::value>::type* = nullptr) {
}

2 个答案:

答案 0 :(得分:8)

改为使用非类型模板参数:

template <class Integer,
    std::enable_if_t<std::is_integral<Integer>::value, int> = 0>
T(Integer n) {
    // ...
}

template <class Float,
    std::enable_if_t<std::is_floating_point<Float>::value, int> = 0>
T(Float n) {
    // ...
}

之所以可行,是因为编译器必须先替换第一个模板参数,然后才能确定value参数的类型。

答案 1 :(得分:1)

解决此问题的一种方法是添加额外的, typename=void参数,以使所有重载都没有相同数量的模板参数。