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-qualifiedstd::initializer_list
types的引用。 [例如: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} );