Why can't I implicitly construct an object giv

2020-08-13 02:03发布

问题:

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?

回答1:

There would be two implicit conversions involved:

  1. to std::string
  2. 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)



回答2:

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_) {}


回答3:

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



回答4:

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



标签: c++