2015-02-06 5 views
14

В C++ 11, новый универсальный синтаксис инициализации также можно использовать для вызова обычного конструктора (который не принимает параметр initializer_list). Хотя, глядя, что это неплохо, я думаю, что это может вызвать проблемы в реальном мире.Универсальная инициализация C++ 11 вызывает неожиданную инициализацию?

Итак, пусть в моем проекте я использую библиотеку, которая поставляется со следующим классом:

class Foo 
{ 
public: 
    Foo(int size, int value); // create 'size' number of elements 
    Foo(initializer_list<int> list); // create elements as in 'list' 
} 

В проекте используется таким образом:

Foo foo{10, 2}; // initialize foo with 2 elements: 10 and 2 

Теперь библиотека получила новое релиз, а в новом выпуске автор удалил второй конструктор, который принимает файл initializer_list (либо по назначению, либо по ошибке). Я не заметил изменений, и мой проект строится счастливо, как и раньше, только с неожиданной инициализацией foo (теперь это 10 элементов вместо 2).

Другая версия этой проблемы состоит в том, что Foo имеет только 1-й конструктор, и вы используете универсальный синтаксис инициализации для init foo, и теперь автор решил добавить 2-й конструктор и что в равной степени вызывает инициализацию foo с помощью разных элементов, не замеченных.

Просто хотел узнать мнение других людей об этом. Это настоящая проблема, или я слишком переживаю? Есть ли решение предотвратить это? Благодарю.

+2

Это, безусловно, хороший аргумент против того, чтобы считать его «универсальным» и пытаться использовать его повсеместно. Используйте правильное имя, «инициализацию списка» и используйте его только тогда, когда вы специально хотите инициализировать из списка. Или когда синтаксис заставляет вас, например, инициализацию в классе или во избежание досадного разбора. (Но это только мое мнение, а не ответ, так как на самом деле нет ответа.) –

+5

Скотт Мейерс очень хорошо описывает это в Эффективном современном C++ в пункте 7, и да, это настоящая проблема. –

+0

Очень крутой вопрос. Может ли кто-нибудь объяснить, почему скобки '()' разрешены для пропуска? – Chiel

ответ

1

Настоящая проблема заключается в том, что API изменился.

Если конструктор был

Foo(int size, int value); 

и вы использовали

Foo foo(10, 2); 

и API был бы изменен на

Foo(int value, int size); 

вы бы с той же проблемой.

+0

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

+0

У вас может быть такая же проблема без инициализатора таким же образом, просто создайте исходный конструктор 'Foo (size_t size, int value)' и новый конструктор 'template Foo (Types ... values) '. Когда вы вызываете исходный конструктор с 'Foo foo (10, 2)', он будет соответствовать новому конструктору. – StenSoft

+0

Действительно, конструктор шаблонов может иметь такой же эффект. Как уже отмечалось выше от Chiel и Aggieboy, если C++ явно сообщает о двусмысленностях в этих случаях и требует, проблему можно избежать. Но я предполагаю, что это может привести к трудностям при использовании класса в шаблоне. –

Смежные вопросы