initializer_list和模板类型推导

4ZM*_*4ZM 34 c++ templates initializer-list c++11

考虑功能:

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

或任何其他期望一个参数具有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'});
Run Code Online (Sandbox Code Playgroud)

我们甚至可以这样写:

const auto il = {'a', 'b', 'c'};
printme(il);
Run Code Online (Sandbox Code Playgroud)

要么

printme<std::initializer_list<char>>({'a', 'b', 'c'});
Run Code Online (Sandbox Code Playgroud)

Lil*_*ard 41

您的第一行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
Run Code Online (Sandbox Code Playgroud)

- 结束例子]

然而auto,§7.1.6.4/ 6明确支持std::initializer_list<>

如果初始化程序是braced-init-list(8.5.4),则std::initializer_list<U>.

  • 我们知道*为什么*这是这种情况?对我来说,如果我想允许模板函数(可能是基于范围的算法)来获取初始化列表参数,我似乎很奇怪,我必须为`std :: initializer_list`提供重载. (6认同)
  • 只是为了完整.这是一种解决问题的方法:http://pastebin.com/huEGwnDt (5认同)
  • @JosephMansfield我没有找到确切的答案,但我怀疑这与用于统一初始化的花括号有关。调用`g({1,2,3})`也可以被理解为`g(Foo(1,2,3))`,其中`Foo`是具有构造函数的三个类的任何类。 (2认同)

Joh*_*hug 10

您还可以重载该函数以显式获取类型为initializer_list的参数.

template<typename T>
void printme(std::initializer_list<T> t) {
  for (auto i : t)
    std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)

  • 不,不会。其他版本仍然可以使用。http://ideone.com/f2yZ7 (2认同)

Pra*_*ian 5

§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
Run Code Online (Sandbox Code Playgroud)

—结束示例]

要使其工作,您可以显式指定模板参数类型。

printme<std::initializer_list<int>>( {1,2,3,4} );
Run Code Online (Sandbox Code Playgroud)