为什么在 C++11/C++14 中对自动和支撑初始值设定项有特殊的类型扣除规则

Why is there a special type deduction rule for auto and braced initializers in C++11/C++14?

本文关键字:规则 类型 C++14 C++11 为什么      更新时间:2023-10-16

在他的CppCon 2014演讲"Type Deduction and Why You Care"中,Scott Meyers提出了为什么在C++11/C++14标准中有一个关于auto和支撑初始值设定项的特殊规则的问题(他的问题从36分05秒开始(。

auto 与大括号初始化列表的组合语义在 §7.1.6.4/6 中定义。


我想了想,也想不出用例。到目前为止,我看到的最接近的东西是Bjarne Stroustrup使用它的一个例子。

在他的 Cpp 2014 演讲"让简单的任务变得简单!"中,他曾经使用 auto 来捕获初始值设定项(但只是作为一种解决方法(。

以下是代码(幻灯片 30 的一部分,37m10s(:

    // auto ss1 = collect({ 1, 2, 3, 4, 5, 6 }, odd); // error: Bummer!
    auto lst = { 1, 2, 3, 4, 5, 6 };
    auto ss2 = collect(lst, odd);    // {1,3,5}

但请注意,这只是一种解决方法。他提到没有必要。相反,他更愿意直接将参数传递给函数。因此,它不能真正作为auto和初始值设定项列表的良好动机。


我对C++的理解还不够深入,无法判断在 Bjarne 的例子中允许初始值设定项列表的缺点,正如他所建议的那样。无论如何,在这种情况下,它将避免需要auto

那么,auto和初始值设定项列表只是本可以更好地解决的问题的解决方法吗?或者有没有很好的例子,其中 §7.1.6.4/6 中的额外自动扣除规则很有用?

基本原理是在 N2640 中,它希望禁止从大括号初始值设定项列表中扣除普通类型参数:

template<class T>
void inc(T, int); // (1)
template<class T>
void inc(std::initializer_list<T>, long); // (2)
inc({1, 2, 3}, 3); // Calls (2). (If deduction had succeeded
                   // for (1), (1) would have been called — a
                   // surprise.)

但为auto划出了一个特殊的例外:

另一方面,能够initializer_list<X>推断出 T具有吸引力,允许:

auto x = { 1, 1, 2, 3, 5 };
f(x);
g(x);

从一开始就被认为是可取的行为 EWG 关于初始值设定项列表的讨论。而不是想出一个 与 {} 列表匹配的参数类型的巧妙推导规则T (我们在本文的早期草图和草稿中追求的选项(, 我们现在更喜欢使用"auto"变量的特殊情况来处理这个问题 初始值设定项为 {} 列表时的扣除。即,对于特定的 使用"auto"类型说明符和 {}-list 初始值设定项,"auto"被推导出为函数 f(initializer_list<T>)而不是函数f(T)

Scott Meyers 在一篇博客文章中解决了这个话题:为什么自动推断 std::initializer_list 对于大括号初始值设定项

像T.C.的答案一样,它也指的是N2640。添加了特殊的扣除规则,以允许这样的代码工作:

 auto x = { 1, 1, 2, 3, 5 };
 f(x);
 g(x);

在博客文章中,斯科特引用了詹姆斯·霍普金的以下解释:

简短的故事是,N2640提出了一种特殊情况,即auto应该推断出支撑的初始值设定项作为initializer_lists,而没有意识到这样做会破坏统一初始化(例如,它使int x{7};auto x{7};非常不同(。N3922 通过(当然!(引入另一种特殊情况来解决这个问题:单参数支撑初始值设定项有自己的规则。

稍微详细一点:N2640 试图保持模板参数推导简单,但试图通过将大括号初始值设定项分配给 auto,允许将大括号初始值设定项传递给两个或多个函数。这在 N2672 中变成了措辞。请注意,Stroustrup 之前在 N2532 中的设计允许对不受约束的模板参数和 auto 进行initializer_lists扣除,这更一致,但也破坏了统一的初始化。

这些都不能解释为什么N3922不只是删除了汽车的特殊情况。这不会导致对代码含义的无声更改,并且会简化语言。