Какие жадные примеры списка инициализаторов скрываются в стандартной библиотеке?
Начиная с 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'
}
Я не смог найти третий пример на этом сайте, и он появился в чате Loungestd::string
конструктор, принимающий счет и символ для использования {}
вместо ()
меняет свое значение с n
копии персонажа на n
-ый символ (обычно из таблицы ASCII), за которым следует другой символ.
Это не учитывается обычным запрещением скобок для сужающих преобразований, потому что 65 является константным выражением, которое может быть представлено как символ и будет сохранять свое первоначальное значение при преобразовании обратно в int (§8.5.4/7, пул 4) (спасибо @JerryCoffin).
Вопрос: есть ли еще примеры, скрывающиеся в стандартной библиотеке, где преобразование ()
конструктор стиля для {}
стиль, жадно соответствует конструктор списка инициализатора?
2 ответа
Я полагаю, с вашими примерами для std::vector<int>
а также std::string
Вы хотели также покрыть другие контейнеры, например, std::list<int>
, std::deque<int>
и т. д., которые имеют такую же проблему, очевидно, как std::vector<int>
, Аналогично int
не единственный тип, так как это также относится к char
, short
, long
и их unsigned
версия (возможно, несколько других целочисленных типов тоже).
Я думаю, что есть также std::valarray<T>
но я не уверен, если T
разрешено быть целым типом. На самом деле, я думаю, что у них другая семантика:
std::valarray<double>(0.0, 3);
std::valarray<double>{0.0, 3};
Есть несколько других стандартных шаблонов классов C++, которые принимают std::initializer_list<T>
в качестве аргумента, но я не думаю, что какой-либо из них имеет перегруженный конструктор, который будет использоваться при использовании скобок вместо фигурных скобок.
Просто в поисках появления initializer_list
,
Все последовательности имеют конструкторы, подобные вектору:
- Deque
- dynarray
- forward_list
- список
- вектор
valarray
basic_string
Неупорядоченные коллекции, есть конструктор, который принимает целое число для определения начального количества сегментов.
- unordered_set
- unordered_multiset
Я думаю, что это все.
#include <unordered_set>
#include <iostream>
int main() {
std::unordered_set<int> f (3);
std::unordered_set<int> g {3};
std::cout << f.size() << "/" << g.size() << std::endl; // prints 0/1.
}