initializer_list和模板types的扣除

考虑一下function:

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

或任何其他函数期望与一个begin()/ end()启用types的一个参数。

为什么以下是非法的?

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

你列出的其他人是合法的,因为参数有一个明确的types,所以模板参数T可以被推断得很好。

你的auto代码片段也可以工作,因为il被认为是std::initializer_list<char> ,因此printme()的模板参数可以被推断出来。


这里唯一的“有趣的”部分是auto会selectstd::initializer_list<char>但是模板参数不会。 这是因为C ++ 11标准的§14.8.2.5/5明确指出这是一个模板参数的非推导上下文:

一个函数参数,其关联参数是一个初始值设定项列表(8.5.4),但该参数没有std :: initializer_list或对可能的cv-qualified std :: initializer_listtypes的引用。 [例:

 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<>

如果初始化器是一个braced-init-list (8.5.4),则使用std::initializer_list<U>

你也可以重载函数来显式地使用initializer_listtypes的参数。

 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-qualified std::initializer_listtypes的引用。 [例如:

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

– 例子]

为了使其工作,您可以明确指定模板参数types。

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