Какие жадные примеры списка инициализаторов скрываются в стандартной библиотеке?

Начиная с 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 ++> chat (в обсуждении с @rightfold, @Abyx и @JerryCoffin), несколько удивительным является то, что преобразование std::string конструктор, принимающий счет и символ для использования {} вместо ()меняет свое значение с n копии персонажа на n-ый символ (обычно из таблицы ASCII), за которым следует другой символ.

Это не учитывается обычным запрещением скобок для сужающих преобразований, потому что 65 является константным выражением, которое может быть представлено в виде символа и сохранит свое первоначальное значение при преобразовании обратно в int (§8.5.4 / 7, пул 4) (спасибо @JerryCoffin).

Вопрос: есть ли еще примеры, скрывающиеся в стандартной библиотеке, где преобразование () конструктор стиля для {} стиль, жадно соответствует конструктор списка инициализатора?

13

Решение

Я полагаю, с вашими примерами для 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> в качестве аргумента, но я не думаю, что любой из них имеет перегруженный конструктор, который будет использоваться при использовании скобок вместо фигурных скобок.

4

Другие решения

Просто в поисках появления 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.
}
2

По вопросам рекламы [email protected]