Рассмотрим функцию:
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'});
Ваша первая строка 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 стандарта C ++ 11 прямо указано, что это не выводимый контекст для аргумента шаблона:
Параметр функции, для которого связанный аргумент является списком инициализатора (8.5.4), но параметр не имеет std :: initializer_list или ссылки на, возможно, cv-квалифицированный тип std :: initializer_list. [Пример:
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>
,
Вы также можете перегрузить функцию, чтобы явно получить аргумент типа initializer_list.
template<typename T>
void printme(std::initializer_list<T> t) {
for (auto i : t)
std::cout << i;
}
Это конкретно рассматривается в § 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
— конец примера]
Чтобы это работало, вы можете явно указать тип аргумента шаблона.
printme<std::initializer_list<int>>( {1,2,3,4} );