24

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

11
  • 8
    It was not a criticism on your question, or your link. Rather a random thought on why people would bother to make a tutorial video, with all kinds of distractions (voice, pacing, environment of choice), instead of a text-based tutorial (which also can be easily edited and updated to include additional information). Just a thought that sprung up when I followed the link, saw "video", and immediately closed the tab because I couldn't be bothered to sit through it all. Ignore me. ;-) Commented Jun 7, 2016 at 7:42
  • 1
    @DevSolar: You think that's weird -- last week, some guy who had asked a question on Stack Overflow and got requests for clarification responded by making a video! Commented Jun 7, 2016 at 8:38
  • 4
    @nwp in a well written tutorial you can get that too, and it may be easier to follow than it would be in a video. A good teacher should be able to communicate as easily with text as with a video lecture Commented Jun 7, 2016 at 8:46
  • 1
    Sinking: For videos, see the last few years of the Going Native conference, explaining fresh new techniques for newer compilers. This includes a great deal due to move semantics available as of C++11. Commented Jun 7, 2016 at 8:58
  • 1
    seriously? Considering only one implicit conversion is to be used at once, this would discredit all the given answers?! Once I thought I understood it..... Commented Jun 7, 2016 at 10:23

3 Answers 3

37

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.

Sign up to request clarification or add additional context in comments.

9 Comments

This, really, should be accepted as the full answer.
The other answers also explained the non-transitive conversion flow. However I need to first understand the whole copy initialization thing first, to recognize your answer as the superior. As soon as I am behind all this I come back and consider changing the accepted mark.
This is a very well organized explanation, kudos
Quick: I believe d1 works with the class as you wrote it. Adding a char* constructor would not be nice.
The compiler is allowed to optimize out the copy! Even so, it must check for availability and ability to call it. Make the copy ctor private and you'll get an error instead.
|
26

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");

1 Comment

You could, but you wouldn't really write that at all. You would write Dog d ("rover");.
17

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");

6 Comments

This answer would be even better, though, if it also explained why the conversion from const char* to std::string cannot be used in the OP's context.
But "rover" isn't a const char* either. So why would this fix the problem? Or why is there a problem in the first place?
I see my problem is not a lack of understanding how to use the converting constructor, but in how strings or char pointers are handled differently.
Another option would be to use "rover"s
Adding that consructor is not nice, as the class needs a string anyway. You don't want every single class that takes string arguments to have another form, especially if there's more than one string argument! You can initialize Dog from a string literal, using direct initialization. I think this answer is not "even better" but misses the point.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.