Consider the following MCVE.
#include <type_traits>
struct A {
template<typename T, typename std::enable_if<std::is_same<T,int>::value,int>::type = 0>
operator T() const { return static_cast<T>(1); }
};
int main() {
int x = 1;
A a;
return x + a;
}
clang compiles it fine. DEMO
But GCC fails with:
error: no match for 'operator+' (operand types are 'int' and 'A')
return x + a;
~~^~~
Question: who is right and why?
User-defined conversions allow you to specify object conversions that are implicitly applied by the compiler, in addition to standard built-in type conversions.
For more information, see Standard Conversions. User-defined conversions perform conversions between user-defined types, or between user-defined types and built-in types. You can implement them as Conversion constructors or as Conversion functions.
There are two types of user-defined conversions: Conversion constructors and conversion functions.
Explanation: The syntax of operator conversion is operator float()const.
I believe clang is right.
To do lookup on +, since at least one argument has class type, we consider member, non-member, and builtin candidates. There aren't any member or non-member candidates, so that's eay enough. There is a builtin candidate for int operator+(int, int), which is the only candidate. That candidate is viable because A can be convertible to int, directly (we have a standard conversion from A to const A& for the implicit object parameter, and then the user defined conversion from that to int, there's no further conversion necessary). As we have one viable candidate, that trivially makes it the best viable candidate.
Note that if A just had operator int() const { return 1; }, gcc would accept it. It's just the conversion function template that fails to be considered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With