正在转发初始值设定项列表表达式

Forwarding initializer list expressions

本文关键字:列表 表达式 转发      更新时间:2023-10-16

Initializer列表表达式对于初始化C++容器非常方便:

std::vector<int>({1, 2, 3})

但是,像{1,2,3}这样的大括号包围的初始值设定项列表表达式似乎只会绑定到接受std::initializer_list<int>的函数,而似乎不会绑定到通用(转发)引用

template <class T>
void foo(T&& v)
{
  std::vector<int>(std::forward<T>(v));
}
int main()
{
  foo({1, 2, 3})
}

该输出:

test2.cpp:11:6: note: template<class U> void foo(U&&)
test2.cpp:11:6: note:   template argument deduction/substitution failed:
test2.cpp:33:13: note:   couldn't deduce template parameter ‘U’

(这是GCC 4.7.2的结果。)

不幸的是,这意味着我们无法转发初始值设定项列表表达式。既然这样做会很方便,我想问一下为什么这不起作用?为什么大括号括起来的初始值设定项列表表达式不能绑定到转发引用?或者这是允许的,也许我的编译器太旧了?

这并不是说它不能绑定到函数的参数;只是编译器无法检测到模板的类型。这编译:

#include <vector>
template <class T>
void foo(T&& v)
{
  std::vector<int>(std::forward<T>(v));
}
int main()
{
  foo(std::initializer_list<int>{1, 2, 3});
}

在这种情况下无法推导初始值设定项列表。这实际上是由〔temp.dexecute.call〕中的标准明确涵盖的:

模板参数推导是通过将每个函数模板参数类型(称为P)与调用的相应参数的类型(称之为A),如下所述。如果CCD_ 5是依赖类型,[…]。否则,初始值设定项列表参数会导致该参数被视为非推导参数上下文(14.8.2.5)。[示例:

template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

这里g的例子正是你的情况——T不是依赖类型,所以这被认为是一个非推导上下文。编译器拒绝您的代码是正确的。