Emi*_* L. 3 c++ standards uniform-initialization auto c++11
考虑用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);
}
Run Code Online (Sandbox Code Playgroud)
编译器输出以下错误:
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>&&}’
Run Code Online (Sandbox Code Playgroud)
指示自动类型扩展为初始化列表而不是std::shared_ptr<type>; 事实上取代{...}与= ...使代码编译为自动扩展到正确的类型.
我有点惊讶的是,这个看似明显的用例未能达到预期的效果.特别是当我回想起新的括号初始化语法被吹捧为最终解决问题的所有解决方案时.
所以我的问题是:这是否符合标准?或者它是一个疏忽甚至是gcc的错误?或者我只是想错了?
Cas*_*sey 10
正如Xeo在评论中所说,这是标准行为.7.1.6.4 auto说明符[dcl.spec.auto]第6段指定:
一旦根据8.3确定了declarator-id的类型,使用declarator-id声明的变量的类型是使用模板参数推导的规则从其初始化程序的类型确定的.让
T是已经确定的可变标识符的类型d.通过用新发明的类型模板参数替换出现来获取P,或者如果初始化器是braced-init-list(8.5.4),则使用.然后使用函数调用(14.8.2.1)中的模板参数推导规则确定推导出的变量类型.TautoUstd::initializer_list<U>dAP是函数模板参数类型,初始化器d是相应的参数.如果扣除失败,则声明格式不正确.
它也被广泛鄙视 - 委员会正在审议一项改变C++ 14行为的提案.C++ 14对广义lambda捕获的支持加剧了这个问题.
更新:在Urbana(参见CWG Motion 16 N4251 WG21 2014-11 Urbana Minutes),委员会将N3922自动扣除新规则从braced-init-list应用到C++ 17工作文件中.他们决定修复特殊情况,允许通过添加另一个特殊案例auto来推断.复制列表初始化的工作方式相同,但是对于带有单个元素的braced-init-list的直接列表初始化,可以直接从该元素中推导出.来自多元素braced-init-list的直接列表初始化现在是不正确的.initializer_listautoauto
这意味着给定
auto x = {42};
Run Code Online (Sandbox Code Playgroud)
x有类型std::initializer_list<int>,但在
auto x{42};
Run Code Online (Sandbox Code Playgroud)
x是一个int.