2015-07-23 3 views
3

Я столкнулся с this статьей, в которой я читал этот пример одним из плакатов. Я привел это здесь для удобства.Равномерное поведение инициализации, различное для разных типов в векторе

struct Foo 
{ 
    Foo(int i) {} // #1 
    Foo() {} 
}; 

int main() 
{ 
    std::vector<Foo> f {10}; 

    std::cout << f.size() << std::endl; 
} 

Приведенные выше код, как написано, излучает «1» (10 является преобразован в Foo с помощью конструктора, который принимает Int, то initializer_list конструктора вектора называется). Если я прокомментирую строку, прокомментированную как # 1, результат равен «10» (список initializer_list не может быть преобразован, поэтому используется конструктор int ).

Вопрос: почему он испускает 10, если конструктор int удален. Я понимаю, что список равномерная инициализация работает в следующем порядке

1-Calls the initializer list if available or possible 
2-Calls the default constructor if available 
3-Does aggregate initialization 

В приведенном выше случае, почему он создает 10 элементов в векторе, так как 1,2 и 3 не представляется возможным? Означает ли это, что при равномерной инициализации вектор элементов всегда может иметь разные типы поведения?

+1

Ваша терминология, кажется, отключена. По умолчанию c'tor - это тот, который может быть вызван без аргументов (если есть несколько таких c'tors, из-за аргументов по умолчанию, то попытка использовать его будет неоднозначной). Это нельзя назвать здесь, потому что это потребует пустых или отсутствующих парсеров/фигурных скобок. Агрегатная инициализация предназначена только для POD без конструктора и не применяется к std :: vector (используется, например, для std :: array и для других структур C-стиля). Если вы измените 2. на «вызов конструктора с совместимыми типами аргументов», это будет иметь больше смысла, но агрегат init. и c'tors действительно либо - или. –

+2

Чтобы уточнить (у меня закончились символы): агрегатная инициализация никогда не является отказом от вызова некоторого конструктора. Он доступен только в том случае, если класс или структура не имеет никакого конструктора. Поэтому, если класс имеет конструктор, но ни конструктор с std :: initializer_list, ни конструктор с совместимыми аргументами не могут быть вызваны, нет никакой резервной копии для агрегации инициализации. Вместо этого программа плохо сформирована. –

+0

@ArneVogel Ответы принадлежат как ответы - не пишите многократные комментарии ... – Barry

ответ

3

Заимствование цитаты из Скотт Мейерс в современном эффективном C++ (курсив в оригинале):

Если, однако, один или несколько конструкторов объявить параметр типа std::initializer_list, звонки с помощью рамно синтаксиса инициализации сильно предпочитает перегрузки с std;:initializer_list s. Строго. Если есть любым способом для компиляторов для толкования вызова с использованием упрощенного инициализатора в качестве конструктора с std::initializer_list, компиляторы будут использовать эту интерпретацию.

Так что, когда у вас есть std::vector<Foo> f {10};, он будет пытаться использовать конструктор vector<Foo>, который принимает initializer_list<Foo>. Если Foo является конструктивным из int, то есть конструктор, который мы используем, - поэтому мы получаем один из Foo, построенный из 10.

Или от standardese, в [over.match.list]:

Когда объекты не-агрегатного типа класса T являются список инициализируется (8.5.4), разрешение перегрузки выбирает конструктор в двух фазах:

(1.1) - Вначале функции-кандидаты являются конструкторами-списками инициализаторов (8.5.4) класса T, а список аргументов состоит из списка инициализаторов как одного аргумента.
(1.2) - Если не найдено никакого жизнеспособного конструктора-списка инициализатора, выполняется повторное разрешение перегрузки, где функции-кандидаты являются конструкторами класса T, а список аргументов состоит из элементов списка инициализаторов.

Если является жизнеспособным инициализатором-лист конструктора, он используется.Если у вас не было конструктора Foo(int), не было бы жизнеспособного конструктора-конструктора инициализатора, и во втором случае разрешение перегрузки обнаружило бы конструктор vector, который принимает размер, - и поэтому вы получите вектор из 10 значений по умолчанию -constructed Foo s.

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