Я обнаружил, что возможность использования синтаксиса списка инициализаторов для класса зависит от того, имеют ли поля класса значения по умолчанию. Зачем?
Чтобы быть точным, рассмотрим следующий код:
class S
{
public:
int a;
};
...
int a;
S s{ a };
Компилируется без проблем. Но если я добавлю значение по умолчанию в поле класса, оно прекратит сборку:
class S
{
public:
int a = 0;
};
...
int a;
S s{ a };
Ошибка 1 ошибка C2440: «инициализация»: невозможно преобразовать из «списка инициализаторов» в «S»
Зачем? Что еще влияет на такую генерацию конструктора?
В C ++ 14, Ваш код корректен и должен компилироваться любым C ++ 14-совместимым компилятором.
В C ++ 11 тем не мение:
Если у вас нет значения по умолчанию для a
Ваш тип является совокупным, и, таким образом, агрегатная инициализация можно выполнить:
Агрегат является одним из следующих типов:
тип массива
тип класса (как правило, структура или объединение), который имеет
- нет частных или защищенных нестатических элементов данных
- нет пользовательских конструкторов, в том числе унаследованных от общедоступных баз (начиная с C ++ 17) (допускаются явно заданные по умолчанию или удаленные конструкторы) (начиная с C ++ 11)
- нет виртуальных, частных или защищенных (начиная с C ++ 17) базовых классов
- нет виртуальных функций-членов
- нет инициализаторов элементов по умолчанию (начиная с C ++ 11, до C ++ 14)
Как только вы добавите значение по умолчанию для атрибута a
ваша инициализация агрегата больше не может быть выполнена, поскольку ваш тип перестал быть агрегатом.
Показанный код компилируется без проблем с gcc 6.1.1. Скорее всего, вы используете старый компилятор, который не полностью поддерживает C ++ 14:
$ cat t.C
class S
{
public:
int a = 0;
};void foo()
{
int a=4;
S s{a};
}
$ g++ -std=c++1z -g -c -o t.o t.C
$ g++ --version
g++ (GCC) 6.1.1 20160510 (Red Hat 6.1.1-2)
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
В обоих случаях конструктор по умолчанию S
не принимает аргументов Форма класса не влияет на генерацию конструктора по умолчанию. Кроме того, не существует неявно сгенерированного конструктора, принимающего int
,
Если S
является совокупный, тогда использование S s = { arguments_opt };
не вызывает S
конструктор. Вместо этого он вызывает то, что называется агрегатная инициализация. Агрегаты являются единственными классами, так что объекты этого класса могут быть созданы без вызова конструктора.
Только если S
является не совокупность, делает S s = { arguments_opt };
попытаться сопоставить список аргументов с параметрами конструктора S
,
(Как объяснено другими, в C ++ 11 обеспечение скобки или равно-инициализатор для нестатического члена данных делает класс не агрегатным).