Подтвердить что ты не робот

Initializer_list и вывод типа шаблона

Рассмотрим функцию:

template<typename T>
void printme(T&& t) {
  for (auto i : t)
    std::cout << i;
}

или любой другой функции, которая ожидает один параметр с типом begin()/end().

Почему следующие незаконные?

printme({'a', 'b', 'c'});

Когда все это законно:

printme(std::vector<char>({'a', 'b', 'c'}));
printme(std::string("abc"));
printme(std::array<char, 3> {'a', 'b', 'c'});

Мы можем даже написать это:

const auto il = {'a', 'b', 'c'};
printme(il);

или

printme<std::initializer_list<char>>({'a', 'b', 'c'});
4b9b3361

Ответ 1

Ваша первая строка printme({'a', 'b', 'c'}) является незаконной, поскольку аргумент шаблона T не может быть выведен. Если вы явно укажете аргумент шаблона, он будет работать, например. printme<vector<char>>({'a', 'b', 'c'}) или printme<initializer_list<char>>({'a', 'b', 'c'}).

Другие, которые вы указали, являются законными, потому что аргумент имеет четко определенный тип, поэтому аргумент шаблона T может быть выведен просто отлично.

Ваш фрагмент с auto также работает, потому что il считается типом std::initializer_list<char>, поэтому аргумент шаблона printme() может быть выведен.


Единственная "забавная" часть здесь состоит в том, что auto будет выбирать тип std::initializer_list<char>, но аргумент шаблона не будет. Это связано с тем, что в § 14.8.2.5/5 стандарта С++ 11 явно указано, что это не выведенный контекст для аргумента шаблона:

Параметр функции, для которого связанный аргумент представляет собой список инициализаторов (8.5.4), но параметр не имеет std:: initializer_list или ссылки на возможный тип std:: initializer_list cv. [Пример:

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

- конец примера]

Однако с auto в § 7.1.6.4/6 имеется явная поддержка std::initializer_list<>

если инициализатор представляет собой скопированный-init-список (8.5.4), с std::initializer_list<U>.

Ответ 2

Вы также можете перегрузить функцию, чтобы явно принять аргумент типа initializer_list.

template<typename T>
void printme(std::initializer_list<T> t) {
  for (auto i : t)
    std::cout << i;
}

Ответ 3

Это специально описано в § 14.8.2.5/5

Параметр функции, для которого связанный аргумент является список инициализаторов, но параметр не имеет std::initializer_list или ссылку на возможную квалификацию cv std::initializer_list. [Пример:

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

-end пример]

Чтобы заставить его работать, вы можете явно указать тип аргумента шаблона.

printme<std::initializer_list<int>>( {1,2,3,4} );