简体   繁体   中英

C++: choosing a `const char *` vs `std::string` when using delegating constructor

Consider the following:

class Foo {
public:
    Foo (const char *in) {
        printf ("C string constructor called\n");
    }
    Foo (std::string const &in) : Foo(in.c_str()) {
        printf ("C++ string constructor called\n");
    }
};
Foo bar ("I never asked for this");
//C string constructor called

So, a constant string is treated as a const char * one.

But what would change, if we make a std::string constructor "primary"?

Can we expect that an std::string object would be created and passed to corresponding constructor without calling a C-string related one?

class Foo {
public:
    Foo (std::string const &in) {
        printf ("C++ string constructor called\n");
    }
    Foo (const char *in) : Foo(std::string (in)) {
        printf ("C string constructor called\n");
    }
};
Foo bar ("I never asked for this");
//C++ string constructor called
//C string constructor called

Again, the C-string constructor was called first .

Is this behavior described in C++ standard, or is it compiler-related?

Would this work the same way for eg templates or overloaded functions?

I compiled with GCC 7.3.0 (MSYS2 x64).

"I never asked for this" is a string literal which consists of const char elements:

Foo bar ("I never asked for this"); // calls Foo (const char *in)

Thus, Foo (const char *in) will always get selected by overload resolution regardless of the "order" in which you declare your constructors.

As seen in your 2nd example,

Foo (const char *in) : Foo(std::string (in))

The delegating constructor is selected and will call the target constructor , as selected by the only member of the initialization list.

There is no such thing as primary constructor in C++.

What you observe is that the delegated to constructor ( target constructor ) body is executed first. Then the body of the constructor that delegates ( delegating constructor ).

Delegating constructor :

In this case, the target constructor is selected by overload resolution and executed first, then the control returns to the delegating constructor and its body is executed.

Overload Resolution and Constructor Delegation are two completely different things that do not influence each other at all.

Overload Resolution avoids implicit conversions when possible.

A string literal like "I never asked for this" is a const char[] , which decays to const char * . That is an exact match for your const char * constructor, so that is the one that gets called. Calling your std::string constructor with a string literal as input would require an implicit conversion, as the compiler would have construct a temporary std::string object to bind to the std::string const & reference.

Had you written this code instead:

Foo bar (std::string("I never asked for this"));

Or this:

std::string str = "I never asked for this";
Foo bar (str);

Then the std::string const & constructor would be called instead of the const char * constructor, as there is no implicit conversion from std::string to const char * .

How constructors delegate to each other is an implementation detail AFTER the compiler decides which constructor to call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM