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'});

26

Решение

Ваша первая строка 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>,

32

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

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

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

Это конкретно рассматривается в § 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} );
4
По вопросам рекламы [email protected]