Так как С++ 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 < С++ > (при обсуждении с @rightfold, @Abyx и @JerryCoffin). Несколько удивительная вещь заключается в том, что преобразование std::string
, использующий счетчик и символ для использования {}
вместо ()
, изменяет его значение из n
копий символа на символ n
-th (обычно из таблицы ASCII), за которым следует другой характер.
Это не улавливается обычным запретом на привязку к сужению конверсий, потому что 65 является постоянным выражением, которое может быть представлено как char и будет сохранять свое исходное значение при преобразовании обратно в int (§8.5.4/7, bullet 4) (спасибо @JerryCoffin).
Вопрос: есть ли еще примеры, скрывающиеся в стандартной библиотеке, где преобразование конструктора стиля ()
в стиль {}
, с жадностью совпадает с конструктором списка инициализаторов?