5

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) {
}
Evan Teran
  • 87,561
  • 32
  • 179
  • 238

2 Answers2

11

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.

Justin
  • 24,288
  • 12
  • 92
  • 142
  • I can't say I understand why the value-based thing gets SFINAE done while the typename-based one doesn't... Could you please explain it a little bit more? So can it be said that the value-based SFINAE is "stronger" than the typename-based? – Martin Pecka Feb 09 '22 at 17:44
1

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.

o11c
  • 15,265
  • 4
  • 50
  • 75