Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conversion operator + conversion constructor = unintuitive behavior?

I don't understand why the code below prints struct Value instead of int (which implies the conversion constructor is converting 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:

Even more bizarre is this (this time it's C++11 only, 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; }
}

Which 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?!

like image 971
user541686 Avatar asked Dec 19 '12 10:12

user541686


People also ask

What are conversion operators in C++?

Conversion Operators in C++ C++ supports object oriented design. So we can create classes of some real world objects as concrete types. Sometimes we need to convert some concrete type objects to some other type objects or some primitive datatypes. To make this conversion we can use conversion operator.

What is a converting constructor?

A constructor that is not declared with the specifier explicit and which can be called with a single parameter (until C++11) is called a converting constructor.

What is a conversion constructor in Java?

A conversion constructor is a single-parameter constructor that is declared without the function specifier explicit . The compiler uses conversion constructors to convert objects from the type of the first parameter to the type of the conversion constructor's class.

Why do we use conversion constructor in C++?

Conversion constructor in C++? The constructors are used to construct objects of a class. Sometimes constructors may take some arguments, or sometimes it does not take arguments. When a constructor takes only one argument then this type of constructors becomes conversion constructor.


1 Answers

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

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 a copy constructor is implicitly defaulted. The governing paragraph is 13.3.1.3 Initialization by constructor [over.match.ctor]:

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

In the second example, deleted functions participate equally in overload resolution; they only affect compilation once overloads have been resolved, when a program that selects a deleted function is ill-formed. The motivating example in the standard is of a class that can only be constructed from floating-point types:

struct onlydouble {
  onlydouble(std::intmax_t) = delete;
  onlydouble(double);
};
like image 77
ecatmur Avatar answered Sep 19 '22 21:09

ecatmur