In the below example, why can't I simply pass a string
to the printFoo()
?
#include <string>
#include <iostream>
using namespace std;
class Foo {
public:
Foo(const Foo &foo) : str(foo.str) {}
Foo(string str) : str(str) {}
string str;
};
void printFoo(Foo foo) {
cout << foo.str << endl;
}
int main() {
Foo foo("qux");
printFoo(foo); // OK
printFoo("qix"); // error: no matching function for call to 'printFoo'
return 0;
}
For whatever reason, I had in my head that a constructor would automatically be determined and used in order to construct an object.
Why can't I do this, but I can pass a char[n]
constant to an argument accepting a std::string
, for example?
There would be two implicit conversions involved:
- to
std::string
- to
Foo
C++ does at most one:
From 4 Standard conversions (N3337)
Standard conversions are implicit conversions with built-in meaning.
Clause 4 enumerates the full set of such conversions. A standard
conversion sequence is a sequence of standard conversions in the
following order:
— Zero or one conversion from the following set:
lvalue-to-rvalue conversion, array-to-pointer conversion, and
function-to-pointer conversion.
— Zero or one conversion from the
following set: integral promotions, floating point promotion, integral
conversions, floating point conversions, floating-integral
conversions, pointer conversions, pointer to member conversions, and
boolean conversions.
— Zero or one qualification conversion.
Also 12.3 Conversions (N3337)
1 Type conversions of class objects can be specified by constructors and
by conversion functions. These conversions are called user-defined
conversions and are used for implicit type conversions (Clause 4), for
initialization (8.5), and for explicit type conversions (5.4, 5.2.9).
2 User-defined conversions are applied only where they are unambiguous
(10.2, 12.3.2). Conversions obey the access control rules (Clause 11).
Access control is applied after ambiguity resolution (3.4).
[...]
4 At most one user-defined
conversion (constructor or conversion function) is implicitly applied
to a single value.
(Emphasis mine)
According to the C++ standard §12.3/4 Conversions [class.conv]:
At most one user-defined conversion (constructor or conversion
function) is implicitly applied to a single value.
Thus, the compiler is not allowed to apply two conversions in a row. That is, firstly from const char[4]
to std::string
and secondly from std::string
to Foo
.
For this to work you would need to define an additional constructor:
Foo(char const *str_) : str(str_) {}
Thats because the compiler is allowed to consider one conversion.
To do what you need to do the compiler would need to plant two conversions.
printFoo("qix");
// Actually needs.
printFoo(Foo(std::string("qix")));
If you change this so you pass a string it will work.
printFoo(std::string("qix"));
The main reason behind all this is string literals have the type char const[<size>]
NOT std::string
As others have mentioned, problem is that 2 conversions needed. You may use s
literal to convert string literal to actual std::string
printFoo("qix"s);
DEMO