initializer_list和模板类型推导

initializer_list and template type deduction

本文关键字:类型 list initializer      更新时间:2023-10-16

考虑函数:

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>,但模板参数不会。这是因为C++11标准的§14.8.2.5/5明确指出,这是模板参数的非推导上下文:

一种函数参数,其关联参数是初始值设定项列表(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<>

如果初始值设定项是支持的初始列表(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或参考可能合格的简历CCD_ 17型。[示例:

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