为什么在 C++11/C++14 中对自动和支撑初始值设定项有特殊的类型扣除规则
Why is there a special type deduction rule for auto and braced initializers in C++11/C++14?
在他的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不只是删除了汽车的特殊情况。这不会导致对代码含义的无声更改,并且会简化语言。
- C++中的严格别名规则和类型别名
- 使用C++11标准的哪些规则来确定({..})中表达式的类型
- 如何在不违反类型别名规则的情况下解释消息负载?
- 强制转换为不相关的引用类型是否违反严格的别名规则?
- POD 类型的二进制 I/O 如何不违反别名规则
- 在 Objective-C++ 中应用于__weak指针时,通过关键字推导类型"auto"规则是什么?
- 有关不完整类型的Sfinae的特殊规则
- 精神X3,如何获得属性类型以匹配规则类型
- C++20 中的严格别名规则是否允许标准 c++ unicode 字符和下划线类型之间"reinterpret
- 初始化中的模板转换运算符类型推导规则是什么?
- 将临时值存储为某种数据类型时,算术运算的标准规则是什么
- MISRA C++规则 14-5-1:在与类型关联的命名空间中声明的泛型函数模板的名称
- 本地类规则是否与c++14返回类型推导一致
- 将字符阵列施放到另一种类型中是否违反了严格的确定规则
- 要求将各种类型的各种类型传递给微控制器上的规则引擎.施放问题
- 隐式数值类型转换的规则
- 在makefile中更改构建规则以构建多种文件类型
- 用删除类型的指针的stof()/stoi()将打破严格的确定规则
- C++函数类型模板参数推导规则
- 为什么提升区域设置不提供字符级别规则类型?