Рассмотрим следующий код:список инициализации агрегатов: когда он может вызвать конструктор копирования?
struct A {
int x;
};
int main() {
A a;
A b{a};
}
эта программа хорошо сформированную на C++ 11 стандарта? В моей копии N3797 говорится инициализация
8.5.4 Списка
[dcl.init.list]
3: Список инициализация объекта или ссылок типа
T
определяются следующим образом:
- ЕслиT
представляет собой совокупность, выполняется агрегатная инициализация (8.5.1).
- В противном случае, еслиT
является специализациейstd::initializer_list<E>
, ...
- В противном случае, еслиT
- тип класса, учитываются конструкторы. Соответствующие конструкторы перечислены, и лучший выбирается с использованием разрешения перегрузки. Если для преобразования любого из типов требуется сужение преобразования, программа плохо сформирована.
- В противном случае, если в списке инициализаций имеется один элемент типаE
, и либоT
не является ссылочным, либо ссылается наE
, объект или ссылка инициализируются из этого элемента; если требуется преобразование сужения для преобразования элемента вT
, программа плохо сформирована.
- В противном случае, еслиT
является ссылочным типом, значение pr-значение, временное для ссылки на тип, наT
, инициализируется или инициализируется списком-списком, в зависимости от типа инициализации для ссылки, а ссылка связанный с этим временным.
- В противном случае, если в списке инициализаторов нет элементов, объект инициализируется значением.
- В противном случае программа плохо сформирована.
Точка примера: тип является агрегатом, но инициализация списка должна вызывать конструктор копирования. На gcc 4.8
и gcc 4.9
, в C++ 11 стандарта, он не:
main.cpp: In function ‘int main()’:
main.cpp:7:8: error: cannot convert ‘A’ to ‘int’ in initialization
A b{a};
^
и говорит A is not convertible to int
или подобное, поскольку совокупная инициализация терпит неудачу. На gcc 5.4
он отлично работает в стандарте C++ 11.
С clang
Вы получаете похожие ошибки с clang-3.5
, 3.6
, и он начинает работать с clang-3.7
.
Я понимаю, что он хорошо сформирован в стандарте C++ 14 и что он упоминается в отчете о дефектах here.
Однако, я не понимаю, почему это считается дефектом в стандарте.
Когда пишет стандарт,
"Если X
, Foo инициализация выполняется. В противном случае, если Y
, бар-инициализация выполняется, .... В противном случае, программа плохо сформированная.",
не означает, что если X
имеет место, но foo-initialization не может быть выполнена, тогда мы должны проверить, выполняется ли Y
, а затем попытаться инициализировать бар?
Это приведет к тому, что пример будет работать, поскольку при сбое инициализации агрегата мы не сопоставим std::initializer_list
, а следующее условие, которое мы сопоставляем, это «T
- это тип класса», а затем мы рассматриваем конструкторы.
Обратите внимание, что это делает, кажется, как она работает в этом модифицированном примере
struct A {
int x;
};
int main() {
A a;
const A & ref;
A b{ref};
}
Все же компиляторы относиться к этому так же, как в предыдущем примере, на C++ 11 и C++ 14 стандартов. Но похоже, что измененная формулировка из записи о дефектах CWG не относится к этому делу. Она гласит:
Если
T
является типом класса и список инициализатора имеет единственный элемент типаcv T
или типа класса, полученный изT
, объекта инициализируются из этого элемента.
http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1467
Но во втором примере кода, список инициализатор технически содержит const T &
. Поэтому я не вижу, как это будет работать, если после сбоя инициализации агрегата не произойдет, мы должны попытаться создать конструкторы.
Я не прав? Не предполагается ли попытка создания конструкторов после сбоя инициализации агрегата?
Вот родственный пример:
#include <iostream>
struct B {
int x;
operator int() const { return 2; }
};
int main() {
B b{1};
B c{b};
std::cout << c.x << std::endl;
}
В clang-3.6
, gcc-4.8
, gcc-4.9
, он печатает 2
, и в clang-3.7
, gcc-5.0
печатает 1
.
Предполагая, что я ошибаюсь, и в стандарте C++ 11 инициализация списка агрегатов должна быть инициализирована агрегатом, и ничего больше, пока не будет введена новая формулировка в отчете о дефектах, является ли это ошибкой, что это происходит, даже когда я выбираю -std=c++11
на новых компиляторах?
Итак, что вы думаете о примере 'struct B'? Вы думаете, что 'gcc' и' clang' используют некоторые функции C++ 14, которые не должны быть доступны в стандарте C++ 11? –
@ChrisBeck: Я думаю, они решили, что это был явный дефект в стандарте C++ 11, и они внедрили исправленную версию. Я подозреваю, что единственная причина, по которой так и не удалось «разрешить», заключалась в том, что они начали делать выпуски C++ намного быстрее, поэтому вместо исправления дефектов в старых стандартах они просто исправляют это в последнюю очередь. –