Search code examples
c++c++17enable-if

"No match" error after introducing std::enable_if


I have an operator (in this case operator&=, but that is not an issue) that works fine, until i introduce std::enable_if_t into the mix.

It is simpler to explain with the code example:

template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>>>
MyClass& MyClass::operator&=(T d)
{ /*... */ }

// then in main
MyClass a;
a &= static_cast<unsigned char>42;
a &= (unsigned long long)47;

If i comment out the std::enable_if_t block, then it compiles and runs as expected, but once i place it in there it produces errors in the format

test.cpp:42:7: error: no match for ‘operator&=’ (operand types are ‘MyClass’ and ‘unsigned char’)
  a &= static_cast<unsigned char>(42);
  ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from test.cpp:4:0:
file.hpp:69:103: note: candidate: template<class T, typename std::enable_if<(is_integral_v<T> && is_unsigned_v<T>), void>::type <anonymous> > MyClass& MyClass::operator&=(T)
  template<typename T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>>> MyClass& operator&=(T d);
                                                                                                  ^~~~~~~~
file.hpp:69:103: note:   template argument deduction/substitution failed:
test.cpp:42:39: note:   couldn't deduce template parameter ‘<anonymous>’
  a &= static_cast<unsigned char>(42);

I feel like i am missing something simple here. I have even already tried hinting the compiler by calling a.operator&=<unsigned char>(static_cast<unsigned char>(42)) to see if it will work, but it doesn't.


Solution

  • You need to use class/typename at the second template parameter in definition of

    template<typename T, class = std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>>>
                         ^^^^^
    MyClass& MyClass::operator&=(T d)
    

    When the condition std::is_integral_v<T> && std::is_unsigned_v<T> is true, enable_if::type is void. Without class void is treated as non-type template parameter what is wrong (void cannot be used as non-type parameter reference).

    By using class/typename the second parametr is defined as type parameter which takes void - class SomeTypeName = void if the condition in enable_if is true, or this function template is discarded from overloads set when enable_if's condition is false.