将列表初始化的对插入到 std::map 中



我正在尝试将仅移动类型插入到地图中。我有以下一段代码:

#include <map>
class Moveable
{
public:
    Moveable() = default;
    Moveable(const Moveable&) = delete;
    Moveable(Moveable&&) = default;
    Moveable& operator=(const Moveable&) = delete;
    Moveable& operator=(Moveable&&) = default;
};
int main() {
    std::map<int,Moveable> my_map;
    Moveable my_moveable_1, my_moveable_2, my_moveable_3;
    my_map.insert(std::pair<int,Moveable>{1, std::move(my_moveable_1)}); // (1)
    my_map.insert(std::make_pair(2, std::move(my_moveable_2)));          // (2)
    my_map.insert({3, std::move(my_moveable_3)});                        // (3)
    return 0;
}

发生的情况是使用 VisualC++ 第 1、2 和 3 行进行编译。在 clang 和 gcc 中,只有 1 和 2 编译,第 3 行给出错误(使用已删除的复制构造函数(。

问题:哪个编译器是正确的,为什么?

在这里试试: rextester

std::map::insert具有以下重载:

// 1.
std::pair<iterator,bool> insert( const value_type& value );
// 2. (since C++11)
template< class P >
std::pair<iterator,bool> insert( P&& value );
// 3. (since C++17)
std::pair<iterator,bool> insert( value_type&& value );

第一个重载显然不能与仅移动类型一起使用。但是第二个重载虽然在 C++11 中可用,但在这里不适用于大括号,因为大括号不会发生模板参数推断(至少在 C++11 中,不确定以后的标准(。

insert 的第一次和第二次调用都在 C++11 或更高版本中工作,因为编译器知道类型,但第三次失败。

C++17 添加了另一个适用于大括号和仅移动类型的重载。现在至于为什么它适用于某些编译器而不是其他编译器,这很可能是由于 C++17 支持级别或编译器标志的差异。

更新:只是为了使其非常明显:使用大括号,我的意思是仅使用大括号(聚合初始化或隐式构造函数调用(,即 insert({k,v}),不是insert(pair<K,V>{k,v})。在后一种情况下,类型是已知的,即使在 C++11 中也可以选择模板化重载。

我已经用 g++ 7.3 测试了您的代码,它可以编译没有错误!

使用 clang++ 5.0.1 它无法编译。

我认为您正在使用 c++20 的功能,因此尚未在所有编译器上准备好支持。

相关内容

  • 没有找到相关文章

最新更新