具有统一初始化的自动将扩展到意外类型
Auto with uniform initialization expands to unexpected type
考虑这个用GCC 4.7.2编译的简短程序g++ -std=c++11 test.cc
#include <memory>
#include <queue>
struct type{
type(int a) : v(a) {}
int v;
};
typedef std::shared_ptr<type> type_ptr;
int main(){
int value = 3;
std::queue<type_ptr> queue;
auto ptr{std::make_shared<type>(value)};
queue.push(ptr);
}
编译器输出以下错误:
src/test.cc: In function ‘int main()’:
src/test.cc:15:17: error: no matching function for call to ‘std::queue<std::shared_ptr<type> >::push(std::initializer_list<std::shared_ptr<type> >&)’
src/test.cc:15:17: note: candidates are:
In file included from /usr/include/c++/4.7/queue:65:0,
from src/test.cc:2:
/usr/include/c++/4.7/bits/stl_queue.h:211:7: note: void std::queue<_Tp, _Sequence>::push(const value_type&) [with _Tp = std::shared_ptr<type>; _Sequence = std::deque<std::shared_ptr<type>, std::allocator<std::shared_ptr<type> > >; std::queue<_Tp, _Sequence>::value_type = std::shared_ptr<type>]
/usr/include/c++/4.7/bits/stl_queue.h:211:7: note: no known conversion for argument 1 from ‘std::initializer_list<std::shared_ptr<type> >’ to ‘const value_type& {aka const std::shared_ptr<type>&}’
/usr/include/c++/4.7/bits/stl_queue.h:216:7: note: void std::queue<_Tp, _Sequence>::push(std::queue<_Tp, _Sequence>::value_type&&) [with _Tp = std::shared_ptr<type>; _Sequence = std::deque<std::shared_ptr<type>, std::allocator<std::shared_ptr<type> > >; std::queue<_Tp, _Sequence>::value_type = std::shared_ptr<type>]
/usr/include/c++/4.7/bits/stl_queue.h:216:7: note: no known conversion for argument 1 from ‘std::initializer_list<std::shared_ptr<type> >’ to ‘std::queue<std::shared_ptr<type> >::value_type&& {aka std::shared_ptr<type>&&}’
指示 auto 类型扩展到初始值设定项列表而不是 std::shared_ptr<type>
;实际上,将 {...}
替换为 = ...
会使代码在 auto 扩展到正确的类型时编译。
我有点惊讶这个看似明显的用例未能达到预期的结果。特别是当我记得新的括号初始化语法被吹捧为初始化问题的最终解决方案时。
所以我的问题是:这是标准中有意的吗?还是疏忽,甚至是 gcc 错误?还是我只是想错了?
正如Xeo在他的评论中所说,这是标准行为。7.1.6.4 自动说明符 [dcl.spec.auto] 第 6 段指定:
根据 8.3 确定声明符 ID 的类型后,使用声明符 ID 的声明变量的类型将使用模板参数推断规则从其初始值设定项的类型确定。设
T
为变量标识符d
确定的类型。通过将auto
的出现次数替换为新发明的类型模板参数U
或者,如果初始值设定项是大括号初始化列表 (8.5.4(,则替换为std::initializer_list<U>
来获取T
P
。A
然后,使用从函数调用 (14.8.2.1( 中推导的模板参数推导规则确定为变量d
推导的类型,其中P
是函数模板参数类型,d
的初始值设定项是相应的参数。如果 扣除失败,声明格式不正确。
它也被广泛鄙视 - 委员会正在审查一项改变C++14行为的提案。C++14对广义lambda捕获的支持加剧了这个问题。
更新:在厄巴纳(见 N4251 WG21 2014-11 厄巴纳会议纪要中的 CWG 议案 16(中,委员会将 N3922 自动从大括号初始化列表中自动扣除的新规则应用于 C++17 工作文件。他们决定修复允许auto
通过添加另一个特殊情况来推断initializer_list
的特殊情况。 auto
与复制列表初始化的工作方式相同,但对于从具有单个元素的大括号初始化列表直接列表初始化auto
该元素直接从该元素推断。来自多元素大括号初始化列表的直接列表初始化现在格式不正确。
这意味着给定
auto x = {42};
x
的类型为 std::initializer_list<int>
,但在
auto x{42};
x
是一个int
.
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 如何在C++中定义扩展到条件语句的宏?
- 使用 Pybind11 将C++扩展到 Python
- "__cplusplus"宏扩展到什么?
- 将矢量的数据扩展到指定大小(插值)
- 如何将模板参数包扩展到一系列模板化参数
- AVX2 根据条件将连续元素扩展到稀疏向量?(如AVX512 VP扩展)
- 符号将11位扩展到32位
- 以编程方式将终端扩展到特定大小
- 将RCPP函数扩展到任何类型的输入向量
- C 将参数包扩展到数组元组
- 将参数包扩展到具有折叠表达式的lambda -GCC与Clang
- 我如何获得Qlabel以扩展到全宽度
- c++hdf5:如何设计易于扩展到新的复合数据类型的程序
- 将 std::list 扩展到 cylic list
- 如何将宏值扩展到宽字符串
- 如何将右值生存期扩展到自定义容器生存期
- 关闭Qt控制台应用程序会终止exec()调用中的进程,并且无法从main()扩展到范围
- 在c++中,当我们创建一个类而不扩展到任何类时
- 具有统一初始化的自动将扩展到意外类型