Julian
Julian

Reputation: 524

How to correctly use converting constructors?

I read that C++ compilers are able to implicitly convert types, when fitting converting constructors or operands are provided. I actually found example code that looks much like this:

class Dog{
    private:
       string name;
    public:
        Dog(string n):name(n){} //This as the converting constructor
}

int main(){
    Dog d = "rover";
}

Whenever I run this code the compiler throws an error message:

conversion from ‘const char [6]’ to non-scalar type ‘Dog’ requested Dog d = "rover";

When compiling I add the compiler option -std=c++11, so it shouldn't be about the C++ version, right?
Examples I found on the internet (at least to me) look quite identical, so I have no clue of what is going wrong here.
My input about this topic comes for example from this video: Convert constructor and overloading operators - thenew moston

Upvotes: 24

Views: 3073

Answers (3)

JDługosz
JDługosz

Reputation: 5642

You also need to understand that you are using copy initialization rather than direct initialization.

They are different, and you need to understand how, and their relationship with explicit. You need to understand how chains of conversions work, with at most one user-defined conversion involved.

Dog d1 ("rover");
Dog d2 = "rover";

The d2 case tries to convert the literal to a Dog, and then copy (move) that to d2. But that would be a double conversion: const char* to string and then string to Dog.

The d1 case constructs d1 passing the argument to the constructor, so only one conversion const char* to string. (In both cases, promoting const char [6] to const char* is in there too but doesn't count toward the "only one" allowed, being in a different category.)

The copy-initialization does not specify "rover" as an argument of the constructor. It says "here is something, but a Dog is needed here". here is the right-hand-side of the copy-init declaration syntax, not any identifiable function. The compiler than has to find a legal conversion.

In the direct-init case, you are simply giving parameters for a function (a constructor). The compiler converts what you gave it into the declared argument type.

Upvotes: 37

songyuanyao
songyuanyao

Reputation: 172894

Note "rover" is not std::string, it's const char[6] (with the null character at the end) (might decay to const char*), to make Dog d = "rover"; work, "rover" needs to be converted to std::string and then converted to Dog.

But user-defined conversion won't be considered twice in one implicit conversion.

(emphasis mine)

User-defined conversion function is invoked on the second stage of the implicit conversion, which consists of zero or one converting constructor or zero or one user-defined conversion function.

You can convert "rover" to std::string explicitly to make it work.

Dog d = std::string("rover");

Upvotes: 26

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

You need another constructor that allows you to construct from a const char*:

Dog(const char* n):name(n){}

Remember that "rover" isn't a std::string, and the type won't be deduced to use the conversion constructor implicitly. As @songyuanyao mentioned in their answer the conversion will be done once only.

Another option is to write:

Dog d = std::string("rover");

Upvotes: 17

Related Questions