C++ 为什么';t emplace_back()是否使用统一初始化?
以下代码:C++ 为什么';t emplace_back()是否使用统一初始化?,c++,vector,c++11,uniform-initialization,C++,Vector,C++11,Uniform Initialization,以下代码: #include <vector> struct S { int x, y; }; int main() { std::vector<S> v; v.emplace_back(0, 0); } #包括 结构 { int x,y; }; int main() { std::向量v; v、 后侵位(0,0); } 使用GCC编译时给出以下错误: In file included from c++/4.7.0/i686-pc-linu
#include <vector>
struct S
{
int x, y;
};
int main()
{
std::vector<S> v;
v.emplace_back(0, 0);
}
#包括
结构
{
int x,y;
};
int main()
{
std::向量v;
v、 后侵位(0,0);
}
使用GCC编译时给出以下错误:
In file included from c++/4.7.0/i686-pc-linux-gnu/bits/c++allocator.h:34:0,
from c++/4.7.0/bits/allocator.h:48,
from c++/4.7.0/vector:62,
from test.cpp:1:
c++/4.7.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = S; _Args = {int, int}; _Tp = S]':
c++/4.7.0/bits/alloc_traits.h:265:4: required from 'static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]'
c++/4.7.0/bits/alloc_traits.h:402:4: required from 'static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>]'
c++/4.7.0/bits/vector.tcc:97:6: required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, int}; _Tp = S; _Alloc = std::allocator<S>]'
test.cpp:11:24: required from here
c++/4.7.0/ext/new_allocator.h:110:4: error: new initializer expression list treated as compound expression [-fpermissive]
c++/4.7.0/ext/new_allocator.h:110:4: error: no matching function for call to 'S::S(int)'
c++/4.7.0/ext/new_allocator.h:110:4: note: candidates are:
test.cpp:3:8: note: S::S()
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided
test.cpp:3:8: note: constexpr S::S(const S&)
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'const S&'
test.cpp:3:8: note: constexpr S::S(S&&)
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'S&&'
在c++/4.7.0/i686 pc linux gnu/bits/c++分配器中包含的文件中。h:34:0,
从c++/4.7.0/bits/allocator.h:48,
从c++/4.7.0/vector:62,
来自测试。cpp:1:
c++/4.7.0/ext/new_allocator.h:在'void u gnu cxx::new_allocator::construct(_Up*,_Args&&&…)[with _Up=S;_Args={int,int};_Tp=S]的实例化中:
c++/4.7.0/bits/alloc_traits.h:265:4:static typename std::enable_if::type std::allocator_traits::_S_构造(_alloc&,_Tp*,_Args&……[with _Tp=S;_Args={int,int};_alloc=std::allocator;typename::enable_if::type=void])
c++/4.7.0/bits/alloc_traits.h:402:4:static void std::allocator_traits::construct(_-alloc&,_-Tp*,_-Args&&…[with _-Tp=S;_-Args={int,int};_-alloc=std::allocator]中的必填项
c++/4.7.0/bits/vector.tcc:97:6:void std::vector::emplace_back(_Args&&…[with _Args={int,int};_Tp=S;_Alloc=std::allocator]中的必填项
测试。cpp:11:24:从这里开始需要
c++/4.7.0/ext/new_allocator.h:110:4:错误:新初始值设定项表达式列表被视为复合表达式[-fppermissive]
c++/4.7.0/ext/new_allocator.h:110:4:错误:调用“S::S(int)”时没有匹配的函数
c++/4.7.0/ext/new_allocator.h:110:4:注意:候选对象是:
test.cpp:3:8:note:S::S()
test.cpp:3:8:注意:候选者需要0个参数,提供1个
test.cpp:3:8:note:constexpr S::S(const S&)
test.cpp:3:8:注意:参数1从'int'到'const S&'没有已知的转换
test.cpp:3:8:note:constexpr S::S(S&&)
test.cpp:3:8:注意:参数1没有从'int'到'S&&'的已知转换
建议vector
使用常规的()
构造函数语法从emplace\u back()的参数构造元素。为什么vector
不使用{}
统一的初始化语法来制作上述示例
在我看来,使用{}
(有构造函数时调用构造函数,但没有构造函数时仍能工作),使用{}
,更符合C++11的精神——毕竟,统一初始化的全部要点是统一使用它——也就是说,到处都是——初始化对象。伟大的思想都是一样的;v) 。我提交了一份缺陷报告,并建议对该主题的标准进行修改
另外,吕克·丹顿帮助我理解了困难
当炮位可建造时(23.2.1
[container.requirements.general]/13)需求用于初始化
如果是对象,则会发生直接初始化。初始化聚合或
将std::initializer\u list构造函数与emplace一起使用需要命名
初始化的类型并移动一个临时文件。这是由于
std::allocator::使用直接初始化构造,而不是
列表初始化(有时称为“统一初始化”)
语法
更改std::allocator::construct以使用列表初始化
除其他外,会优先考虑std::initializer\u list吗
构造函数重载,在非直观和
不可更改的方式-emplace_无法返回以访问
构造函数被std::initializer_list抢占
重新实现推回
std::vector<std::vector<int>> v;
v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization
std::vector v;
v、 后置(3,4);//v[0]={4,4,4},而不是列表初始化中的{3,4}
建议的折衷方案是将SFINAE与std::is_可构造一起使用,
它测试直接初始化是否格式正确。如果
is_constructable如果为false,则为另一个选项
选择std::allocator::construct重载,该重载使用
列表初始化。因为列表初始化总是依赖于
直接初始化时,用户将看到诊断消息,就像
始终使用列表初始化(统一初始化),
因为直接初始化重载不能失败
我可以看到两个角落的案例,暴露了这个方案中的漏洞。一个发生
当std::initializer\u列表的参数满足
构造函数,例如尝试在
上面的例子。解决方法是显式指定
std::初始值设定项\列表类型,如中所示
v、 放回(std::初始值设定项列表(3,4))。因为这和
语义就好像std::initializer_list被推导出来一样,似乎有
这里没什么问题
另一种情况是用于聚合初始化的参数
满足构造函数。因为聚合不能具有用户定义的
构造函数,这要求
聚合类型不能从聚合类型隐式转换,并且
初始值设定项列表有一个元素。解决办法是
为第二个成员提供初始值设定项。仍然不可能做到这一点
就地构造仅包含一个非静态数据成员的聚合
从可转换类型到聚合自身类型的转换。这
看起来是个可以接受的小洞
人们可以发明一种语言支持类型,在init列表中完美地转发语法大括号。然后你可以说emplace_back({a,b,…})@johanneschaub litb:IMHO,这更像是std::initializer_list
应该是什么。但是对std::allocator
的简单修改应该可以解决问题。@johanneschaub litb安放的优势在于创建不可移动的对象。为什么能够放置集装箱很重要?同样,请记住,initializer\u list
也是不可移动的,并且总是制作一份副本