SFINAE Constructors [duplicate]

2019-06-28 00:22发布

问题:

This question already has an answer here:

  • SFINAE working in return type but not as template parameter 3 answers
  • Template specialization and enable_if problems [duplicate] 1 answer

I have been liking SFINAE syntax like this for functions, seems to generally work well!

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

But am running into an issue when I want to do this as well in the same class...

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

Getting errors such as this:

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

Shouldn't these constructors only exist for the appropriate types and never at the same time? Why do they conflict?

Am I being a bit thick here?

This on the other hand does work (but I don't like the syntax as much):

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) {
}

回答1:

Use a non-type template parameter instead:

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) {
    // ...
}

This works because the compiler has to substitute the first template parameter before it can determine the type of the value parameter.



回答2:

One way to fix this is to add extra , typename=void arguments so that none of the overloads has the same number of template parameters.



标签: c++ sfinae