15

Исполняемые продуцируемые лязгом 3.5.0 и GCC 4.9.1 из кодаПочему Foo ({}) вызывает Foo (0) вместо Foo()?

#include <iostream> 

struct Foo 
{ 
    Foo() { std::cout << "Foo()" << std::endl; } 
    Foo(int x) { std::cout << "Foo(int = " << x << ")" << std::endl; } 
    Foo(int x, int y) { std::cout << "Foo(int = " << x << ", int = " << y << ")" << std::endl; } 
}; 

int main()     // Output 
{       // --------------------- 
    auto a = Foo();   // Foo() 
    auto b = Foo(1);  // Foo(int = 1) 
    auto c = Foo(2, 3);  // Foo(int = 2, int = 3) 
    auto d = Foo{};   // Foo() 
    auto e = Foo{1};  // Foo(int = 1) 
    auto f = Foo{2, 3};  // Foo(int = 2, int = 3) 
    auto g = Foo({});  // Foo(int = 0)   <<< Why? 
    auto h = Foo({1});  // Foo(int = 1) 
    auto i = Foo({2, 3}); // Foo(int = 2, int = 3) 
} 

ведут себя, как прокомментировал.

От cppreference: cpp/language/list initialization:

[...] 

T({ arg1, arg2, ... }) (7) 

[...] 

Эффекты инициализации списка объекта типа Т являются:

Если T представляет собой агрегат типа, совокупная инициализация выполняется.

В противном случае, если список бит-init пуст, а T - тип класса с конструктором по умолчанию, выполняется инициализация значения.

[...] 

Я пришел к выводу, что Foo({}) должен вызывать конструктор по умолчанию.

Где ошибка?

+4

Ошибка указана в cppreference. – Casey

+2

Исправлено cppreference, чтобы прочитать «Эффекты инициализации списка объекта типа« T »из * не скобки в скобках-init-list * are ...» были бы яснее? – Casey

+0

@ Casey Я бы сказал нет. И сказал бы, что 'T ({...})' is * not * инициализация списка объекта типа 'T', а не добавлять неопределенные формулировки, которые могут быть неверно истолкованы. Cpprefrerence уже не утверждает, что это так. Но с вашим предложенным исправлением он будет читать, что 'T ({...})' - это инициализация списка объекта типа 'T' из скопированного списка инициализации в скобках, который не является * случаем. Это инициализация списка любого параметра, который имеет выбранный конструктор. –

ответ

18

конструктор по умолчанию применяется только, если вы используете одну единственную пару либо скобки:

auto a = Foo();   // Foo() 
auto b = Foo{};   // Foo() 

Foo({}) вместо этого будет вызывать только конструкторы с пустым списком в качестве аргумента, копировать-лист инициализации параметра независимо выбирается конструктор. [Dcl.init]/16:

Если тип назначения (возможно, резюме квалифицированных) Тип класса:
- Если инициализация прямой инициализации [...] Конструкторы рассматриваются. Соответствующие конструкторы перечислены (13.3.1.3), а наилучшая выбирается путем перегрузки (13.3). Выбранный таким образом конструктор вызывается в , инициализируя объект, с выражением инициализатора или выражение-список как его аргумент (ы). Если конструктор не применяется, или , разрешение перегрузки неоднозначно, инициализация плохо сформирована.

У вас есть один аргумент: пустой бит-init-list. Существует последовательность инициализации списка, преобразующая {} в int, поэтому конструктор Foo(int) выбирается с помощью разрешения перегрузки. Параметр инициализируется на ноль, так как {} подразумевает value-intialization, который для скаляров подразумевает zero-initialization.

Там нет ошибка в cppreferences документации либо: Для (7) говорится, что

7) в функциональном выражении литой или другой прямой инициализации, с рамно-Init-лист, используемый в качестве аргумент конструктора

Это явно приводит к такому же результату, как и в приведенной выше цитате: Конструктор вызывается с (пустым) состоящим из списка команд.

+6

+1 Чтобы уточнить для OP, код в этом случае эквивалентен 'auto g = Foo (int {});' и 'int {} == 0'. – cdhowie

+1

, говоря о нестандартных подходах, в «Visual Studio/msvc», когда «список» содержит 1 литерал, который может быть интерпретирован как интегральный тип, например. '{42}', это не список - как и должно быть в соответствии со стандартом, - но это «реальное» целое число, что касается компилятора - msvc; пример 'auto a = {1}', 'a' является целым числом, если вы используете' msvc'. – user2485710

+0

@ user2485710: Вы уверены, что это нестандартно? Хотя я не уделял пристального внимания, я действительно считаю, что я прочитал 'auto a = {1}' is * предполагается *, чтобы вывести 'int' в качестве типа. – Hurkyl

Смежные вопросы