为什么花括号初始化器的自动和模板类型推导不同?

我知道,给定一个花括号初始化器,auto 将推导出 std::initializer_list 的类型,而模板类型推导将失败:

auto var = { 1, 2, 3 };//类型推导为 std::initializer_list模板void f(T 参数);f({ 1, 2, 3 });//不编译;类型推导失败

我什至知道这是在 C++11 标准中指定的地方:14.8.2.5/5 bullet 5:

<块引用>

[如果程序有,它是一个非推导的上下文]一个函数参数,它的关联参数是一个初始化列表(8.5.4)但是参数没有 std::initializer_list 或对可能有 cv 限定的 std::initializer_list 的引用类型.[ 示例:

模板 void g(T);

g({1,2,3});//错误:没有为 T 推导出参数

―结束示例 ]

我不知道或不明白的是为什么存在类型推导行为的这种差异.C++14 CD 中的规范与 C++11 中的规范相同,因此大概标准化委员会不会将 C++11 行为视为缺陷.

有谁知道为什么 auto 推导出一个花括号初始化器的类型,但不允许模板?虽然对这可能是原因"这种形式的推测性解释很有趣,但我对那些知道标准为何如此编写的人的解释特别感兴趣.

解决方案

模板不做任何演绎的重要原因有两个(我记得和负责人讨论的两个)

  • 对未来语言扩展的担忧(您可以发明多种含义 - 如果我们想为带括号的初始化列表函数参数引入完美转发呢?)

  • 大括号有时可以有效地初始化一个依赖的函数参数

<块引用>

template无效分配(T&d,const T& s);

int main() {向量v;分配(v, { 1, 2, 3 });}

如果 T 将在右侧推导出到 initializer_list 但在左侧推导出 vector,这会因为自相矛盾的论证推论而失败.

autoinitializer_list 的推导是有争议的.存在 C++-after-14 删除它的提议(并禁止使用 { }{a, b} 进行初始化,并使 {a} 推导出a的类型).

I understand that, given a braced initializer, auto will deduce a type of std::initializer_list, while template type deduction will fail:

auto var = { 1, 2, 3 };   // type deduced as std::initializer_list<int>

template<class T> void f(T parameter);

f({ 1, 2, 3 });          // doesn't compile; type deduction fails

I even know where this is specified in the C++11 standard: 14.8.2.5/5 bullet 5:

[It's a non-deduced context if the program has] A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list type. [ Example:

template void g(T);

g({1,2,3}); // error: no argument deduced for T

―end example ]

What I don't know or understand is why this difference in type deduction behavior exists. The specification in the C++14 CD is the same as in C++11, so presumably the standardization committee doesn't view the C++11 behavior as a defect.

Does anybody know why auto deduces a type for a braced initializer, but templates are not permitted to? While speculative explanations of the form "this could be the reason" are interesting, I'm especially interested in explanations from people who know why the standard was written the way it was.

解决方案

There are two important reasons for templates not to do any deduction (the two that I remember in a discussion with the guy in charge)

  • Concerns about future language extensions (there are multiple meanings you could invent - what about if we wanted to introduce perfect forwarding for braced init list function arguments?)

  • The braces can sometimes validly initialize a function parameter that is dependent

template<typename T>
void assign(T &d, const T& s);

int main() {
  vector<int> v;
  assign(v, { 1, 2, 3 });
}

If T would be deduced at the right side to initializer_list<int> but at the left side to vector<int>, this would fail to work because of a contradictional argument deduction.

The deduction for auto to initializer_list<T> is controversial. There exist a proposal for C++-after-14 to remove it (and to ban initialization with { } or {a, b}, and to make {a} deduce to the type of a).

相关文章