Учтите следующее:
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).
"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))
делегирующий конструктор выбран и будет вызывать целевой конструктор, по выбору единственного члена списка инициализации.
Там нет такого понятия, как первичный конструктор в C ++.
То, что вы наблюдаете, — то, что делегировано конструктору (целевой конструктор) тело выполнено первым. Затем тело конструктора, который делегирует (делегирующий конструктор).
В этом случае целевой конструктор выбирается разрешением перегрузки и выполняется сначала, затем элемент управления возвращается к делегирующий конструктор и его тело выполнено.
Разрешение перегрузки а также Делегация конструктора это две совершенно разные вещи, которые не влияют друг на друга вообще.
Разрешение перегрузки позволяет избежать неявных преобразований, когда это возможно.
Строковый литерал как "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 *
,
Как конструкторы делегируют друг другу детали реализации ПОСЛЕ того, как компилятор решит который конструктор для вызова.