В говорить о списках инициализации, Я понял, что Страуструп в основном говорит, что синтаксис новой конструкции с фигурными скобками предполагаемый быть общей заменой всех предыдущих синтаксисов конструкции:
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
,
Брейс-инициализация работает везде, где используется инициализатор. Существуют ситуации, когда вам нужно использовать парены, чтобы получить доступ к конструктору, к которому инициализатор фигурных скобок не может получить доступ, но они встречаются редко.
std::vector<int> v(1,1);
std::vector<int> v{1,1};
vector<int>
случается, имеет специализированный конструктор, который занимает два int
s и поэтому неоднозначно пытается построить вектор два int
с долго. Неоднозначный конструктор существует только для обратной совместимости. Новые классы не должны быть определены с конструкторами, которые будут конфликтовать с initializer_list.
Неоднозначность разрешается тем фактом, что синтаксис инициализации фигурной скобки предпочитает конструкторы initializer_list перед другими конструкторами, которые в противном случае соответствовали бы. Если вы хотите устранить неоднозначность в пользу использования конструктора non-initializer_list, то вы не можете использовать инициализацию скобок.
Бьярне Страуструп пишет
Равномерное использование инициализации {} стало возможным только в C ++ 11, поэтому более старый код C ++ использует () и = initialization. Следовательно, () и = могут быть вам более знакомы. Однако я не знаю никакой логической причины, чтобы предпочесть нотацию (), за исключением редкого случая, когда нужно различать инициализацию со списком элементов и списком аргументов конструктора.
— Язык программирования C ++, четвертое издание §17.3.2.1
Ваш пример кода совершенно легален и должен работать как положено. Ошибка, которую вы получаете, это просто ошибка в GCC. Clang и VC ++ 2012 оба принимают код.
Других решений пока нет …