Conversion operator + conversion constructor = unintuitive behavior?

I don’t understand why the code below prints struct Value instead of int (which implies that the conversion constructor is converted to Value instead of int ). (Visual C ++ 2012)

Why is this happening? Why does the compiler completely ignore the Value(int) constructor?

 #include <iostream> #include <type_info> using namespace std; struct Value { Value(int) { } }; struct Convertible { template<class T> operator T() const { throw typeid(T).name(); } }; int main() { try { Value w((Convertible())); } catch (char const *s) { cerr << s << endl; } } 

Edit:

This is even stranger (this time it is only C ++ 11, on GCC 4.7.2):

 #include <iostream> #include <typeinfo> using namespace std; struct Value { Value(Value const &) = delete; Value(int) { } }; struct Convertible { template<class T> operator T() const { throw typeid(T).name(); } }; int main() { try { Value w((Convertible())); } catch (char const *s) { cerr << s << endl; } } 

What gives:

 source.cpp: In function 'int main()': source.cpp:21:32: error: call of overloaded 'Value(Convertible)' is ambiguous source.cpp:21:32: note: candidates are: source.cpp:9:3: note: Value::Value(int) source.cpp:8:3: note: Value::Value(const Value&) <deleted> 

If the copy constructor is deleted, then why is there any ambiguity ?!

+11
c ++ visual-c ++ implicit-conversion
Dec 19 '12 at 10:43
source share
2 answers

In the first example, Visual Studio is incorrect; the challenge is ambiguous. gcc in C ++ 03 mode:

 source.cpp:21:34: error: call of overloaded 'Value(Convertible)' is ambiguous source.cpp:21:34: note: candidates are: source.cpp:9:5: note: Value::Value(int) source.cpp:6:8: note: Value::Value(const Value&) 

Recall that the copy constructor is implicitly defaulted. Control paragraph 13.3.1.3 Initialization by constructor [over.match.ctor] :

When class type objects have direct initialization [...], the constructor selects the overload resolution. For direct initialization, candidate functions are all constructors of the class of the initialized object.

In the second example, remote functions are equally involved in overload resolution; they only affect compilation after overloads have been overloaded, when the program that selects the function to be deleted is poorly formed. The motivational example in the standard refers to a class that can only be built from floating point types:

 struct onlydouble { onlydouble(std::intmax_t) = delete; onlydouble(double); }; 
+8
Dec 19 '12 at 11:39
source share
β€” -

I tried your code (only in Visual Studio version).

Since you have built-in copy-CTOR, I think your main resource is:

 int main() { try { Value w((struct Value)(Convertible())); } catch (char const *s) { cerr << s << endl; } } 

The compiler decided to use your copy of CTOR, not Value (int).

Change it to:

 int main() { try { Value w((int)(Convertible())); } catch (char const *s) { cerr << s << endl; } } 

He printed "int".

+1
Dec 19 '12 at 11:25
source share



All Articles