rub*_*nvb 10 c++ aggregate c++11 emplace
好像这段代码:
#include <string>
#include <vector>
struct bla
{
std::string a;
int b;
};
int main()
{
std::vector<bla> v;
v.emplace_back("string", 42);
}
Run Code Online (Sandbox Code Playgroud)
可以在这种情况下正常工作,但它没有(我理解为什么).给bla
构造函数解决了这个问题,但是删除了类型的聚合性,这可能会产生深远的影响.
这是标准中的疏忽吗?或者我错过了某些会在我脸上爆炸的情况,或者它不像我想的那么有用?
23.2.1/15.5
T是来自args的EmplaceConstructible到X,对于零个或多个参数args,意味着以下表达式格式正确:
allocator_traits<A>::construct(m, p, args)
23.2.1/15
[注意:容器调用
allocator_traits<A>::construct(m, p, args)
使用args在p处构造元素.std::allocator
将调用默认构造::new((void*)p) T(args)
,但专用分配器可以选择不同的定义. - 尾注]
因此,默认分配器使用构造函数,更改此行为可能会导致向后兼容性丢失.您可以在此答案中阅读更多内容/sf/answers/614810311/.
还有一个问题是"迈向更完美的转发"以及一些关于它的未来的随机讨论.
这是标准中的疏忽吗?
它被认为是标准中的一个开放缺陷,跟踪为LWG#2089.但是一个很好的解决方案是难以捉摸的.
根本问题来自这样一个事实:你不能只是毫不犹豫地使用braced-init-lists.具有构造函数的类型的列表初始化实际上可以隐藏构造函数,这样某些构造函数就无法通过列表初始化进行调用.这是vector<int> v{1, 2};
问题所在.这创建了一个2元素vector
,而不是1元素向量,其唯一元素是2.
因此,您不能在通用上下文中使用列表初始化allocator::construct
.
这让我们:
如果可能的话,我认为有一个SFINAE技巧可以做到这一点,否则求助于也适用于聚合的大括号init.
这需要一种is_aggregate
类型特征.目前还不存在,没有人提出它的存在.哦,当然,你可以使用is_constructible
,因为该问题的拟议解决方案.但是有一个问题:它有效地创建了list-initilaization的替代方案.
考虑vector<int>
之前的例子.{1, 2}
被解释为两个元素initializer_list
.但通过emplace
,它将被解释为调用两个整数构造函数,因为is_constructible
从这两个元素将是真的.这导致了这个问题:
vector<vector<float>> fvec;
fvec.emplace(1.0f, 2.0f);
vector<vector<int>> ivec;
ivec.emplace(1, 2);
Run Code Online (Sandbox Code Playgroud)
这些做了两件完全不同的事情.在这种fvec
情况下,它执行列表初始化,因为vector<float>
不能从两个浮点数构造.在这种ivec
情况下,它调用一个构造函数,因为它vector<int>
可以从两个整数构造.
因此,您需要将列表初始化限制allocator::construct
为仅T
在聚合时才起作用.
即使你这样做,你也必须将这个SFINAE技巧传播到所有使用间接初始化的地方.这包括any/variant/optional
的in_place
建设者和炮位,make_shared/unique
电话等,其中没有使用allocator::construct
.
并且这不计算需要这种间接初始化的用户代码.如果用户没有进行与C++标准库相同的初始化,那么人们会感到不安.
这是一个棘手的问题,要解决的方法是不将间接初始化API分成允许聚合的组和不允许聚合的组.有许多可能的解决方案,但没有一个是理想的.
归档时间: |
|
查看次数: |
519 次 |
最近记录: |