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

StackOverflow https://stackoverflow.com/questions/19847960

Вопрос

Начиная с 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'
}

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

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

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

Это было полезно?

Решение

Я полагаю, с вашими примерами для 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.

  • Все последовательности у них есть конструкторы, как у вектора:

    • дек
    • Dynarray
    • forward_list
    • список
    • вектор
  • Валаррей

  • basic_string

  • Неупопорядоченные коллекции, существует конструктор, который требует целого числа, чтобы определить начальное количество ведра.

    • Неупорядоченное_SET
    • Неупорядоченный_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.
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top