Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SFINAE with enable_if and overloading

I've done some looking around, but was unable to find a solution to my specific problem.

I have the code:

template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value || std::is_enum<T>::value, std::string>::type
    convertToString(const T argument) { return std::to_string(argument); }

std::string convertToString(std::string string);

What the code is supposed to do: Use the template version for any numeric type (int, float, double and also ENum) and use the std::string version for anything else.

The code itself compiles fine, however when I pass the function a class, which has a operator const char * overload (which is a viable constructor for std::string), it throws me the following bulk of messages:

no matching function for call to 'SQL_Connection::convertToString(ClassName &)’

candidate: template<class T> typename std::enable_if<(std::is_arithmetic<_Tp>::value || std::is_enum<_Tp>::value), std::__cxx11::basic_string<char> >::type convertToString(T)
 convertToString(const T argument) { return std::to_string(argument); }
 ^~~~~~~~~~~~~~~

template argument deduction/substitution failed:
In substitution of ‘template<class T> typename std::enable_if<(std::is_arithmetic<_Tp>::value || std::is_enum<_Tp>::value), std::__cxx11::basic_string<char> >::type convertToString(T) [with T = ClassName]’:

I've been trying to wrap my head around enable_if and what it does, but at this point I find myself stumped.

Why isn't it falling back to the std::string overload, when it clearly is neither arithmetic nor an ENum?

If I explicitly convert the object to string or const char *, it works as expected.

Thank you very much for your help.

Additional info: I'm using C++11 and g++ 7.3.0 on an Ubuntu system.

like image 568
Refugnic Eternium Avatar asked Jun 03 '19 08:06

Refugnic Eternium


1 Answers

Your usage of enable_if is correct and the problem is not in the function template at all. The thing is that the following won't compile either:

std::string convertToString(std::string string);
struct Foo{
    operator const char*(){...}
};
Foo foo; 
converToString(foo);

The reason is that the compiler is only allowed to do 1 user-defined conversion per passed parameter to match function arguments. In this case it would have to do 2 - Foo->const char* and const char*->std::string.

like image 135
Quimby Avatar answered Nov 14 '22 19:11

Quimby