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?
maheris aconst char[6], andsamis aconst char[4], and both decay toconst char *implicitly, but none of them is actually astd::string.In function calls, the C++ standard allows an implicit conversion to be performed if there’s a non-
explicitconstructor 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 aconst char *; the target type isstd::string, which has a constructor that accepts aconst char *; such constructor is called, and thePersonconstructor correctly receives hisstd::stringparameter.In the second case, this is not happening:
Persondoes not have a constructor that accepts aconst char *, but only a constructor that accepts astd::string. To reach the desiredPersontype the compiler would have to first convert theconst char *tostd::string, and then call thePersonconstructor. 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
greetto be called with a C-style string you should either:create a constructor for
Personwhich accept a C-style string (const char *), so that it can be constructed directly from aconst char *, without going through the prohibited extra conversioncreate another overload for
greetto accept anstd::string.On the other hand, IMO the cleaner alternative is just leave it as it is; the caller will just have to write