В инициализации класса и списке инициализаторов
Недавно я обнаружил, что нельзя одновременно указывать инициализацию класса и список инициализаторов. Сбой следующего кода:
struct s
{
int i=0;
};
int main() {
s s1; //s1.i = 0
//s s2={42}; //fails
return 0;
}
Если я удаляю инициализацию класса in, список инициализаторов работает нормально!
Может кто-нибудь объяснить мне, почему такая вещь не допускается?
2 ответа
На самом деле это разрешено в C++14.
struct s
{
int i=0;
};
int main() {
s s1;
s s2 = {42}; // succeeds
}
Вероятно, ваш компилятор просто не реализует новое правило в C++14. Однако последняя версия clang принимает это и делает все правильно в режиме C++14.
Когда в C++11 была добавлена инициализация в классе, она была указана так, что она не позволяла классу быть агрегатом. Это было сделано потому, что в то время концепция агрегирования была тесно связана с типами PoD, которые должны быть тривиально конструируемыми. Наличие инициализации в классе означает, что тип больше не является тривиально конструируемым. Однако с тех пор эти две концепции стали более независимыми, и поэтому для C++ 14 было принято короткое предложение, отменяющее это решение.
Эта инициализация:
s s1 = { 42 };
требует, чтобы s
быть агрегатом или иметь действительный конструктор, например, int или std::initializer_list
,
Когда вы добавляете инициализацию члена в точке объявления, вы отображаете свой класс s
неагрегированный, поэтому вы больше не можете использовать агрегатную инициализацию.
Вы можете использовать тот же синтаксис инициализации для неагрегата, добавив конструктор:
struct s
{
s(int i) : i(i) {}
int i=0;
};
Я считаю, что это ограничение было смягчено для C++14.
См. Что такое агрегаты... для получения дополнительной информации.