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