C ++: выбор `const char *` vs `std :: string` при использовании делегирующего конструктора

Учтите следующее:

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

Итак, постоянная string рассматривается как const char * один.

Но что изменится, если мы сделаем std::string конструктор «первичный»?

Можем ли мы ожидать, что std::string объект будет создан и передан соответствующему конструктору без вызова связанной с C-строкой?

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

Опять же, конструктор C-строки был назван первый.

Это поведение описано в стандарте C ++, или это связано с компилятором?

Будет ли это работать так же, например, для шаблоны или перегруженные функции?

Я скомпилировал с GCC 7.3.0 (MSYS2 x64).

1

Решение

"I never asked for this" это строковый литерал который состоит из const char элементы:

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

Таким образом, Foo (const char *in) всегда получит выбранный по разрешению перегрузки несмотря на «порядка», в котором вы объявляете свои конструкторы.

Как видно из вашего второго примера,

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

делегирующий конструктор выбран и будет вызывать целевой конструктор, по выбору единственного члена списка инициализации.

3

Другие решения

Там нет такого понятия, как первичный конструктор в C ++.

То, что вы наблюдаете, — то, что делегировано конструктору (целевой конструктор) тело выполнено первым. Затем тело конструктора, который делегирует (делегирующий конструктор).

Делегирующий конструктор:

В этом случае целевой конструктор выбирается разрешением перегрузки и выполняется сначала, затем элемент управления возвращается к делегирующий конструктор и его тело выполнено.

2

Разрешение перегрузки а также Делегация конструктора это две совершенно разные вещи, которые не влияют друг на друга вообще.

Разрешение перегрузки позволяет избежать неявных преобразований, когда это возможно.

Строковый литерал как "I never asked for this" это const char[]который разлагается на const char *, Это точное соответствие для вашего const char * конструктор, так что это тот, который вызывается. Зовет ваш std::string конструктор со строковым литералом в качестве входных данных потребует неявного преобразования, поскольку компилятор должен будет создать временный std::string объект связать с std::string const & ссылка.

Если бы вы написали этот код вместо этого:

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

Или это:

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

Тогда std::string const & конструктор будет вызываться вместо const char * конструктор, так как нет неявного преобразования из std::string в const char *,

Как конструкторы делегируют друг другу детали реализации ПОСЛЕ того, как компилятор решит который конструктор для вызова.

1
По вопросам рекламы [email protected]