Унифицированная инициализация не копируется, когда объект не имеет данных

При обновлении некоторого кода для использования единообразной инициализации я подумал, что это будет заменой современной подстановки для стиля «старого стиля» в скобках. Я знаю, что это не всегда так (очевидный пример, vector ), но я наткнулся на другое отличие, которое я не понимаю.

 class Object { public: Object() = default; Object(const Object&) = default; }; int main() { Object o; Object copy{o}; // error Object copy2(o); // OK } 

не удается скомпилировать под clang3.5 с ошибкой: (также не выполняется под gcc)

 error: excess elements in struct initializer 

Для Object есть два разных изменения, которые делают эту работу. Либо добавляя к нему элемент данных, либо предоставляя ему пустой конструктор конструктора копии

 class Object { private: int i; // this fixes it public: Object() = default; Object(const Object&) { } // and/or this fixes it as well }; 

Я не понимаю, почему это должно иметь значение.

    Ответ Йоханнеса полезен, но позвольте мне подробнее рассказать, почему это происходит в настоящее время.

    Оба изменения, которые вы описываете, влияют на ваш class, заставляя его перейти от агрегата к не совокупности. См. C ++ 11 (N3485) § 8.5.1 / 1:

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

    Конструктор с определением = default считается не определяемым пользователем.

    Затем, перейдя к инициализации списка в § 8.5.4, мы видим:

    Список-инициализация объекта или ссылки типа T определяется следующим образом:

    • Если T является агрегатом, выполняется агрегатная инициализация

    А потом куча разделов «В противном случае …». Таким образом, изменение любого из них позволяет вызывать конструктор вместо выполнения агрегатной инициализации.

    Новый предложенный standardese для определения инициализации списка (как показано в ссылке Johannes’s) обеспечивает приоритетный случай одного элемента в списке и имеет тип (или действительно близкий к) тип инициализируемого объекта. Агрегатная инициализация тогда будет главным приоритетом после этого.

    Это известная ошибка и, мы надеемся, будет исправлена ​​в C ++ 17 (не для C ++ 14, см. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467 ) , Ваша структура является агрегированной, поэтому для ее инициализации с {someElement} должен быть хотя бы один элемент данных, как вы обнаружили. Попробуйте предоставить operator int(); и вы увидите, что он компилируется.

    Давайте будем гением компьютера.