Reputation: 524
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
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
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