具有显式构造函数的类是不是需要在 emplace 中使用分段构造?
Posted
技术标签:
【中文标题】具有显式构造函数的类是不是需要在 emplace 中使用分段构造?【英文标题】:Do classes with explicit constructors require piecewise_construct in emplace?具有显式构造函数的类是否需要在 emplace 中使用分段构造? 【发布时间】:2016-12-11 23:11:34 【问题描述】:如果我使用 explicit
构造函数创建结构
struct A
int x;
explicit A(int x):x(x);
;
然后将它用作std::map
中的mapped_type
,我就可以使用分段构造函数来代替:
#include <map>
std::map<int, A> foo;
foo.emplace(
std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(10)
);
但是当我尝试使用移动或模板构造函数时,我得到错误并且无法编译:
foo.emplace(std::make_pair(2, 20)); // <-- doesn't work
foo.emplace(3, 30); // <-- doesn't work
这里发生了什么?直到现在,我还没有意识到这些不同的用法之间存在很大差异。我想,使用 pair move 构造函数,从std::pair<int, A>
... 进行隐式转换可能是有意义的,但为什么必须在模板构造函数中发生这种情况?那么为什么不使用分段构造函数呢??
我查了一下,但 std::map::emplace
和 explicit
的文档并没有真正为我澄清这一点。
【问题讨论】:
编译器/版本? gcc 版本 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) 【参考方案1】:在N4387 之前,pair<T1, T2>
的构造函数采用U
/V
do not exist 除非U
可以隐式转换为T1
并且V
可以隐式转换为T2
:
template<class U, class V> constexpr pair(U&& x, V&& y);
要求:
is_constructible<first_type, U&&>::value
是true
和is_constructible<second_type, V&&>::value
是true
。效果:构造函数用
std::forward<U>(x)
初始化first
,用std::forward<V>(y)
初始化second
。备注: 如果
U
不能隐式转换为first_type
或V
不能隐式转换为second_type
,则此构造函数应 不参与重载决议。
const pair<U, V>&
和 pair<U, V>&&
构造函数也是如此。
由于这些构造函数实际上不存在,你后面的两个emplace
s 将不起作用。
N4387 更改了这里的规则,如果这两种类型都可以从相应的参数类型构造,但至少有一种不能从参数类型隐式转换,那么这些构造函数将变为 explicit
。因此,在 C++17 中,所有三个 emplace
s 都将编译。另外,正如论文addresses a defect report raising pretty much this exact issue(其中几篇),实现也可以选择在早期的标准模式下实现它。
【讨论】:
以上是关于具有显式构造函数的类是不是需要在 emplace 中使用分段构造?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::map emplace 需要 gcc 上的复制构造函数?
为啥我会使用 push_back 而不是 emplace_back?