В инициализации класса и списке инициализаторов

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

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.

См. Что такое агрегаты... для получения дополнительной информации.

Другие вопросы по тегам