Enabling C++ constructor subject to say std::is_floating_point<T>

I’m trying to enable a default constructor only if the class’s template
parameter is floating point. Note T is not a parameter type nor return type
but the class template type.

template <typename T>
  struct Thing
{
    const T x;
    Thing( T t) : x(t) {}
    //only turn on this constructor if T is floating point
    Thing() : x(std::numeric_limits<T>::quiet_NaN()) {}
};

//...

Thing<double> dt;
Thing<float> ft;
Thing<int> it1;
Thing<int> it2(3);

I tried putting the following in front of the constructor

template <std::enable_if_t<std::is_floating_point<T>::value, bool> = true>

And I tried putting the std::enable_if_t...= true stuff as an argument to the
default constructor (and various other attempts).

Both of these tries rightfully complains about it1 so that’s good, but when I remove that, they both also complain about it2! I don’t understand and can’t find the magic incantation.

Thanks for any insights.

I forgot to mention, I’m stuck on C++17.

>Solution :

Use requires:

Thing() requires std::is_floating_point_v<T>
    : x(std::numeric_limits<T>::quiet_NaN())
{}

Or, in C++17:

template <typename U = T, std::enable_if_t<std::is_floating_point_v<U>, std::nullptr_t> = nullptr>
Thing()
    : x(std::numeric_limits<T>::quiet_NaN())
{}

The SFINAE condition must depend on a template parameter of the function itself. Otherwise it can be checked when the class is first instantiated, even if the function isn’t used.

I also tweaked a few things, purely for style.

Leave a Reply