C++ 为什么我需要在map::emplace中为不可复制对象的单个arg构造函数使用分段_构造?

C++ 为什么我需要在map::emplace中为不可复制对象的单个arg构造函数使用分段_构造?,c++,c++11,map,std-pair,emplace,C++,C++11,Map,Std Pair,Emplace,以下代码不会在gcc 4.8.2上编译。 问题是此代码将尝试复制构造一个std::pair,但由于struct A缺少复制和移动构造函数,因此无法执行该操作 gcc在这里失败了还是我遗漏了什么 #include <map> struct A { int bla; A(int blub):bla(blub){} A(A&&) = delete; A(const A&) = delete; A& operator=(A&&

以下代码不会在gcc 4.8.2上编译。 问题是此代码将尝试复制构造一个
std::pair
,但由于
struct A
缺少复制和移动构造函数,因此无法执行该操作

gcc在这里失败了还是我遗漏了什么

#include <map>
struct A
{
  int bla;
  A(int blub):bla(blub){}
  A(A&&) = delete;
  A(const A&) = delete;
  A& operator=(A&&) = delete;
  A& operator=(const A&) = delete;
};
int main()
{
  std::map<int, A> map;
  map.emplace(1, 2); // doesn't work
  map.emplace(std::piecewise_construct,
          std::forward_as_tuple(1),
          std::forward_as_tuple(2)
  ); // works like a charm
  return 0;
}
#包括
结构A
{
内布拉;
A(int blub):bla(blub){}
A(A&&)=删除;
A(常数A&)=删除;
A&运算符=(A&&)=删除;
A&运算符=(常量A&)=删除;
};
int main()
{
地图;
map.emplace(1,2);//不起作用
地图安放(标准::分段构造,
std::转发作为元组(1),
标准::转发作为元组(2)
);//很有魅力
返回0;
}

据我所知,问题不是由
map::emplace
引起的,而是由
pair
的构造函数引起的:

#include <map>

struct A
{
    A(int) {}
    A(A&&) = delete;
    A(A const&) = delete;
};

int main()
{
    std::pair<int, A> x(1, 4); // error
}
也就是说,
std::is_可构造分析并试图通过使构造函数显式而不是拒绝它来改善这种情况。N4387在Lenexa会议上被投票选为C++1z

下面介绍C++11规则

[pairs.pair]/7-9中描述了我期望调用的构造函数

实际上被称为非标准的:

// DR 811.
template<class _U1,
         class = typename enable_if<is_convertible<_U1, _T1>::value>::type>
constexpr pair(_U1&& __x, const _T2& __y)
: first(std::forward<_U1>(__x)), second(__y) { }
当且仅当以下变量定义对于某些发明变量
t
格式良好时,应满足模板专门化
的谓词条件是可构造的:

T t(create<Args>()...);
如果且 仅当以下代码中的返回表达式格式良好时,包括任何隐式转换 要选择函数的返回类型,请执行以下操作:

To test() {
  return create<From>();
}
结构合理;然而

A test() {
  return create<int>();
}
A测试(){
返回create();
}

创建类型为
a
的临时文件,并尝试将其移动到返回值中(复制初始化)。这会选择已删除的ctor
A(A&&)
,因此格式不正确。

据我所知,问题不是由
map::emplace
引起的,而是由
pair
的构造函数引起的:

#include <map>

struct A
{
    A(int) {}
    A(A&&) = delete;
    A(A const&) = delete;
};

int main()
{
    std::pair<int, A> x(1, 4); // error
}
也就是说,
std::is_可构造分析并试图通过使构造函数显式而不是拒绝它来改善这种情况。N4387在Lenexa会议上被投票选为C++1z

下面介绍C++11规则

[pairs.pair]/7-9中描述了我期望调用的构造函数

实际上被称为非标准的:

// DR 811.
template<class _U1,
         class = typename enable_if<is_convertible<_U1, _T1>::value>::type>
constexpr pair(_U1&& __x, const _T2& __y)
: first(std::forward<_U1>(__x)), second(__y) { }
当且仅当以下变量定义对于某些发明变量
t
格式良好时,应满足模板专门化
的谓词条件是可构造的:

T t(create<Args>()...);
如果且 仅当以下代码中的返回表达式格式良好时,包括任何隐式转换 要选择函数的返回类型,请执行以下操作:

To test() {
  return create<From>();
}
结构合理;然而

A test() {
  return create<int>();
}
A测试(){
返回create();
}

创建类型为
a
的临时文件,并尝试将其移动到返回值中(复制初始化)。这选择了删除的ctor
A(A&&
,因此格式不正确。

似乎不是
map
的错,而是
对的错:@dyp请参见相关问题:@remyabel Great!这是一个dup/相关的,我得出了与jogojapan类似的结论。然而,我认为问题出在
pair
,而不是
map
。似乎这不是
map
,而是
pair
:@dyp请看一个相关问题:@remyabel很棒!这是一个dup/相关的,我得出了与jogojapan类似的结论。然而,问题出在
pair
,而不是
map
。多么奇怪的问题:(@ker谢谢。虽然我认为如果没有那个非标准的ctor,那么应该使用取两个
常量&
的ctor,这也会失败。所以我认为问题是拒绝
U1&&,U2&&
ctor,尽管这似乎是一个合理的选择。我还猜测libstdc++实现者会“责怪”标准,但如果
是可转换的
(或标准中相应的措辞),可能会引发讨论是有意的。使用
is_convertible
是有意的,正如其中明确说明的那样,
is_convertible
的使用,但也改进了这方面的内容,为不可复制、不可移动的类型选择更好的构造函数。@dyp,下一次邮寄中将有N4064的新版本,它可能会被接受ted将在下个月的会议上发言。至于指责该标准,删除
is_convertible
约束将打破比试图在地图中放置不可移动对象的程序更重要的程序。这些约束被添加到该标准中是有充分理由的,libstdc++和libc++遵守这些约束是有充分理由的,而不仅仅是为了学究ally遵循标准。如果不遵循标准,我真的不确定您希望实现做什么。@JonathanWakely在阅读N3680之后,我理解了使用
是可转换的
的原因。请不要把我的“指责标准”看得太重。感谢您提供有关N4064状态的信息。多么奇怪的问题:(@ker谢谢。虽然我认为如果没有那个非标准的ctor,那么应该使用取两个
常量&
的ctor,这也会失败。所以我认为问题是拒绝
U1&&,U2&&
ctor,尽管这似乎是一个合理的选择。我还猜测libstdc++实现者会“责怪”标准,但如果打算使用
可转换
(或标准中的相应措辞),可能会引发讨论。使用
可转换
是有目的的,这一点非常明确
A test() {
  return create<int>();
}