Насколько универсален синтаксис конструкции {}?

В говорить о списках инициализации, Я понял, что Страуструп в основном говорит, что синтаксис новой конструкции с фигурными скобками предполагаемый быть общей заменой всех предыдущих синтаксисов конструкции:

X x1(); // most vexing parse ... doesn't work as intended
X x2(x1);
X x3 = x1;
X x4 = X();

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

Итак, вопрос в том, насколько универсален этот синтаксис? Возможно ли никогда не использовать конструкцию старого стиля в новом коде C ++ 11 или есть ситуации, когда вы иметь вернуться?


Этот вопрос был вызван / мотивирован, когда я столкнулся со следующей ошибкой, которая, по моему мнению, является ошибкой в ​​компиляторе (но я был бы рад исправить ее).

struct X {};

int main() {
X x;
X& y{x}; // works with (x)
X& z{y}; // works with (y)
}

Который не компилируется на g ++ 4.7.1 и не на Ideone’s 4.5.1.

prog.cpp: In function 'int main()':
prog.cpp:5:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'
prog.cpp:6:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'

Обратите внимание, что это работает, когда я заменяю X с int,

6

Решение

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

std::vector<int> v(1,1);
std::vector<int> v{1,1};

vector<int> случается, имеет специализированный конструктор, который занимает два ints и поэтому неоднозначно пытается построить вектор два intс долго. Неоднозначный конструктор существует только для обратной совместимости. Новые классы не должны быть определены с конструкторами, которые будут конфликтовать с initializer_list.

Неоднозначность разрешается тем фактом, что синтаксис инициализации фигурной скобки предпочитает конструкторы initializer_list перед другими конструкторами, которые в противном случае соответствовали бы. Если вы хотите устранить неоднозначность в пользу использования конструктора non-initializer_list, то вы не можете использовать инициализацию скобок.


Бьярне Страуструп пишет

Равномерное использование инициализации {} стало возможным только в C ++ 11, поэтому более старый код C ++ использует () и = initialization. Следовательно, () и = могут быть вам более знакомы. Однако я не знаю никакой логической причины, чтобы предпочесть нотацию (), за исключением редкого случая, когда нужно различать инициализацию со списком элементов и списком аргументов конструктора.

                                                         — Язык программирования C ++, четвертое издание §17.3.2.1


Ваш пример кода совершенно легален и должен работать как положено. Ошибка, которую вы получаете, это просто ошибка в GCC. Clang и VC ++ 2012 оба принимают код.

9

Другие решения

Других решений пока нет …