好像是this code:
#include <string>
#include <vector>
struct bla
{
std::string a;
int b;
};
int main()
{
std::vector<bla> v;
v.emplace_back("string", 42);
}
在这种情况下,可以正常工作,但它没有(我理解为什么)。给bla
构造函数解决了这个问题,但删除了类型的聚合性,这可能会产生深远的影响。
这是标准中的疏忽吗?或者我错过了某些会在我脸上爆炸的情况,或者它不像我想的那么有用?
答案 0 :(得分:5)
23.2.1 / 15.5
对于零个或多个参数,T是EmplaceConstructible到args中的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)
,但专门的分配器可以选择不同的定义。 - 后注]
因此,默认分配器使用构造函数,更改此行为可能会导致向后兼容性丢失。您可以在此答案https://stackoverflow.com/a/8783004/4759200中阅读更多内容。
还有一个问题"Towards more perfect forwarding"和一些随机discussion关于它的未来。
答案 1 :(得分:5)
这是标准中的疏忽吗?
它被认为是标准中的开放缺陷,跟踪为LWG #2089。但是很难解决这个问题。
根本问题来自这样一个事实:你不能只是毫不犹豫地使用braced-init-lists。具有构造函数的类型的列表初始化实际上可以隐藏构造函数,这样某些构造函数就无法通过列表初始化进行调用。这是vector<int> v{1, 2};
问题。这会创建一个2元素vector
,而不是1元素向量,其唯一元素是2。
因此,您不能在allocator::construct
等通用上下文中使用列表初始化。
这将我们带到:
我认为如果可能的话,有一个SFINAE技巧可以做到这一点,否则使用也适用于聚合的大括号init。
这需要is_aggregate
类型特征。目前尚不存在,没有人提出它的存在。哦,当然,您可以使用is_constructible
来解决问题。但问题是:它有效地创建了列表初始化的替代方案。
考虑之前的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);
这两个完全不同。在fvec
情况下,它执行列表初始化,因为vector<float>
不能从两个浮点数构造。在ivec
的情况下,它调用构造函数,因为vector<int>
可以从两个整数构造。
因此,需要将allocator::construct
中的列表初始化限制为仅在T
是聚合时才有效。
即使你这样做了,你也必须将这个SFINAE技巧传播到使用间接初始化的地方的 all 。其中包括any/variant/optional
in_place
个make_shared/unique
构造函数和进驻,allocator::construct
调用等等,其中没有一个使用osht=pd.DataFrame(filename+sheetname)
delimited table Example:
Country;Company;Product
US;ABC;XYZ
US;ABD;XYY
。
这并不计算需要这种间接初始化的用户代码。如果用户不进行与C ++标准库相同的初始化操作,那么人们就会感到不安。
这是一个难以解决的问题,它不会将间接初始化API分成允许聚合和组的组。有many possible solutions,但没有一个是理想的。