Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't c++ recognize a string when trying to convert it into another type?

Tags:

c++

casting

I have a fairly simple class that looks like this:

class Person {
    public:

        Person(string name): _name(name) {};

        void greet(const Person& person) const {
            cout << "Hello, " <<  person._name << "!" << endl;
        };

    private:
        string _name;
};

Note that the greet method takes a parameter of the Person type. When I pass it a Person object, it works as expected. Now let's pass it a string as a parameter in this way:

Person maher("maher");
maher.greet("sam");

When trying to run that code in QT (on a machine running ubuntu), it generates the following error: no matching function for call to ‘Person::greet(const char [4])’

I was able to resolve this error by casting the string in this way: maher.greet(string("sam"));

My question is the following: Why can't c++ 'see' that I'm passing a string to the greet method? Does it have anything to do with the fact that the greet method accepts a Person object?

like image 280
Maher4Ever Avatar asked Dec 17 '22 09:12

Maher4Ever


1 Answers

maher is a const char[6], and sam is a const char[4], and both decay to const char * implicitly, but none of them is actually a std::string.

In function calls, the C++ standard allows an implicit conversion to be performed if there's a non-explicit constructor of the target type that accepts the type of the actual value passed to the function.

This is what happens when you call the constructor: you pass a const char[6], which automatically decays to a const char *; the target type is std::string, which has a constructor that accepts a const char *; such constructor is called, and the Person constructor correctly receives his std::string parameter.

In the second case, this is not happening: Person does not have a constructor that accepts a const char *, but only a constructor that accepts a std::string. To reach the desired Person type the compiler would have to first convert the const char * to std::string, and then call the Person constructor. This double conversion is not allowed, mainly because overloading resolution would become a complete mess (which already is) with lots of ambiguous cases.

If you want to allow greet to be called with a C-style string you should either:

  • create a constructor for Person which accept a C-style string (const char *), so that it can be constructed directly from a const char *, without going through the prohibited extra conversion

  • create another overload for greet to accept an std::string.

On the other hand, IMO the cleaner alternative is just leave it as it is; the caller will just have to write

maher.greet(std::string("sam"));
like image 90
Matteo Italia Avatar answered Dec 31 '22 00:12

Matteo Italia