Инициализация структуры с помощью агрегатной инициализации и инициализаторов членов

Рассмотрим следующий пример:

#include <iostream>
#include <string>
struct ABC
{
    std::string str;
    unsigned int id ;/* = 0 : error: no matching constructor for initialization of 'ABC'*/
};

int main()
{
    ABC abc{"hi", 0};
    std::cout << abc.str << " " << abc.id <<   std::endl;
    return 0;
}

При определении структуры ABC без значения по умолчанию для id clang 3.x и gcc 4.8.x скомпилируйте код без проблем. Однако после добавления аргумента по умолчанию для "id" я получаю сообщение об ошибке:

13 : error: no matching constructor for initialization of 'ABC'
ABC abc{"hi", 0};
^ ~~~~~~~~~
4 : note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided
struct ABC
^
4 : note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided
4 : note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 2 were provided
1 error generated.
Compilation failed

С технической точки зрения, что происходит, когда я определяю идентификатор с аргументом по умолчанию и почему в этом случае невозможна инициализация агрегата? Я неявно определяю какой-то конструктор?

Ответы

Ответ 1

Бьярне Страуструп и Ричард Смит подняли вопрос об объединенной инициализации, а инициаторы-члены не работали вместе.

Определение агрегата слегка изменено в стандартах С++ 11 и С++ 14.

Из стандартного черновика С++ 11 n3337 в разделе 8.5.1 говорится, что:

Агрегат - это массив или класс (раздел 9) без каких-либо пользовательских конструкторы (12.1), нет скобки или равные инициализаторы для нестатических членов данных (9.2), нет частных или защищенных нестатических элементов данных (Раздел 11), нет базовых классов (раздел 10) и нет виртуальных функций (10.3).

Но С++ 14 standard draft n3797 в разделе 8.5.1 говорит, что:

Агрегат - это массив или класс (раздел 9) без каких-либо пользовательских конструкторы (12.1), частные или защищенные нестатические элементы данных (Раздел 11), нет базовых классов (раздел 10) и нет виртуальных функций (10.3).

Итак, когда вы используете в инициализаторе члена класса (, т.е. равном инициализаторе) для члена данных id в С++ 11, он больше не остается агрегированным, и вы не можете написать ABC abc{"hi", 0}; для инициализации a struct ABC. Поскольку после этого он больше не остается агрегированным. Но ваш код действителен в С++ 14. (См. Живое демо здесь).

Ответ 2

В С++ структура и классы одинаковы, за исключением того, что у структур есть публичные члены по умолчанию и классы имеют частные. Если вы хотите использовать начальные значения, я думаю, вам нужно написать конструктор или использовать что-то вроде этого:

struct ABC
{
    std::string str;
    unsigned int id;
} ABC_default = {"init", 0 }; //initial values

int main()
{
    ABC abc = ABC_default;
    std::cout << abc.str << " " << abc.id << std::endl;
    return 0;
}