Начиная с C++11, контейнеры стандартной библиотеки и std::string
имеют конструкторы, принимающие список инициализаторов. Этот конструктор имеет приоритет над другими конструкторами (даже, как указано @JohannesSchaub-litb в комментариях, даже игнорируя другие критерии «наилучшего соответствия»). Это приводит к нескольким хорошо известным ловушкам при преобразовании всех форм конструкторов в скобках ()
в их версии с фигурными скобками {}
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <string>
void print(std::vector<int> const& v)
{
std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
}
void print(std::string const& s)
{
std::cout << s << "\n";
}
int main()
{
// well-known
print(std::vector<int>{ 11, 22 }); // 11, 22, not 11 copies of 22
print(std::vector<int>{ 11 }); // 11, not 11 copies of 0
// more surprising
print(std::string{ 65, 'C' }); // AC, not 65 copies of 'C'
}
Я не смог найти третий пример на этом сайте, и этот вопрос всплыл в чате Lounge‹C++> (в обсуждении с @rightfold, @Abyx и @JerryCoffin). Несколько удивительно то, что преобразование конструктора std::string
принимает count и символ для использования {}
вместо ()
изменяет свое значение с n
копий символа на n
-й символ (обычно из таблицы ASCII), за которым следует другой символ.
Это не улавливается обычным запретом фигурных скобок на сужающие преобразования, потому что 65 — это постоянное выражение, которое может быть представлено как char и сохранит свое исходное значение при обратном преобразовании в int (§8.5.4/7, маркер 4) (спасибо к @JerryCoffin).
Вопрос: есть ли в стандартной библиотеке еще примеры, в которых преобразование конструктора стиля ()
в стиль {}
жадно соответствует конструктору списка инициализаторов?
string
,valarray
, все контейнеры,min
/max
/minmax
, регулярные выражения, некоторые случайные распределения иseed_seq
. - person Kerrek SB   schedule 08.11.2013initializer_list<T>
был добавлен в язык; очень редко вы когда-либо создавали контейнер с известным во время компиляции количеством объектов. Все, что я делаю, это вводит глупые пограничные случаи. - person Simple   schedule 08.11.2013initializer_list
. Таким образом,{}
вызывает конструктор по умолчанию, а неinitializer_list
нулевой длины. Если в вашем классе нет конструктора по умолчанию, будет использоваться конструкторinitializer_list
с нулевыми элементами. (Если есть несколько конструкторовinitializer_list
, вы получите ошибку неоднозначности.) - person CTMacUser   schedule 09.11.2013