[英]Forwarded in-place construction and list-initialization
通过转发就地构造,我指的是std :: allocator :: construct和各种emplace方法,例如std :: vector :: emplace_back 。 我只是发现在C ++中转发的就地构造不能(无法?)利用列表初始化语法。 结果,似乎永远无法转发就位构造聚合。 我只想确保转发的就地构造是否不支持列表初始化以及聚合类型。 这是由于语言的限制吗? 有人可以提供有关此问题的标准的参考吗? 以下是说明:
虽然我们可以像这样直接进行就地施工
int(*p)[3] = ...;
new(p) int[3]{1, 2, 3};
我们不能像
std::allocator<int[3]> allo;
allo.construct(p, 1, 2, 3);
尽管{}
被称为统一初始化语法,但它远非通用。
举两个例子:
size_t a = 3;
size_t b = 1;
std::vector<size_t> v1{a,b};
std::vector<size_t> v2(a,b);
在第一种情况下,我们构造一个包含两个元素3
和1
的向量。
在第二种情况下,我们创建一个包含1,1,1
个1
副本的向量。
现场例子 。
因此,在某些情况下,基于{}
的构造会导致与()
构造不同的行为。 而且,在上述情况下,无法使用{}
构造(我知道)来达到“ 1的3个副本”语法。 但是,可以通过简单地显式创建一个初始化列表并将其传递给()
来处理{3,2}
情况。
由于大多数带有初始值设定项列表的类型都可以通过显式传递初始值设定项列表来构建,而C ++标准库是针对具有构造函数的类型而不是没有构造函数的类型而设计的,因此C ++标准库几乎使用()
而不是{}
。
缺点是无法通过此机制放置要进行列表初始化的类型。
从理论上讲,可以将使用{}
构造的list_emplace
方法添加到每个接口。 我鼓励您提出这一建议!
std::allocator
的construct()
(以及std::allocator_traits
提供的默认实现)指定为使用()
::new((void *)p) U(std::forward<Args>(args)...)
(请参阅[allocator.members] / p12,[allocator.traits.members] / p5)。
此时将其更改为{}
是不切实际的,因为它会静默地破坏现有代码:
std::vector<std::vector<int>> foo;
foo.emplace_back(10, 10); // add a vector of ten 10s with (); two 10s with {}
如果()
不起作用,则存在LWG问题 ,使其无法使用{}
。 我们将不得不看委员会是否同意这个方向。
@Yakk指出了这种方法的潜在缺点:
foo.emplace_back(10); // ten 0s
foo.emplace_back(10, 10); // ten 10s
foo.emplace_back(10, 10, 10); // three(!) 10s
一个类似的问题(请参阅N2215的附录B)导致决定列表初始化将始终偏爱initializer_list
构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.