简体   繁体   English

std :: make_pair,std :: unordered_map以及键类型中的move构造函数的用法

[英]std::make_pair, std::unordered_map and usage of move constructor from key type

Given following struct: 给出以下结构:

struct FieldNo
{
    FieldNo() : a('0'), b('0') {}
    FieldNo(char a_, char b_) : a(a_), b(_b) {}
    // copy construction and assigment not allowed
    FieldNo(const FieldNo& other) = delete;
    FieldNo& operator=(const FieldNo& other) = delete;
    // move construction and assignment ok
    FieldNo(FieldNo&& other) = default;
    FieldNo& operator=(FieldNo&& other) = default; 

    char a;
    char b;
};

enum class Members : int8_t
{
    FOO,
    BAR
};

I am using FieldNo as key and Member as value for an std::unordered_map. 我正在使用FieldNo作为键,将Member作为std :: unordered_map的值。 Ommitting the code for the hash creation function, my map is defined as following: 省略哈希创建函数的代码,我的地图定义如下:

typedef std::unordered_map<FieldNo, Members, FieldNoHasher> MyMapT;

Later I use following method to initialize and return to the caller 后来我用下面的方法初始化并返回到调用者

const MyMapT& map()
{
   static const MyMapT fields = 
   {
       std::make_pair(FieldNo('0', '5'), Members::FOO),
       std::make_pair(FieldNo('1', 'X'), Members::BAR)
   }
   return fields;
}

At first the copy constructor was not deleted and everything worked fine. 最初,复制构造函数未删除,并且一切正常。

As I deleted to copy constructor I am getting loads of errors in insertion and put here the most relevant one: 当我删除要复制的构造函数时,我在插入过程中遇到了很多错误,并将最相关的错误放在这里:

[build] 
[build] /usr/include/c++/8/ext/new_allocator.h:136:4: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const FieldNo; _T2 = Members]’
[build]   { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
[build]     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] In file included from /usr/include/c++/8/bits/stl_algobase.h:64,
[build]                  from /usr/include/c++/8/bits/char_traits.h:39,
[build]                  from /usr/include/c++/8/ios:40,
[build]                  from /usr/include/c++/8/istream:38,
[build]                  from /usr/include/c++/8/fstream:38,
[build]                  from 
[build] /usr/include/c++/8/bits/stl_pair.h:303:17: note: ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const FieldNo; _T2 = Members]’ is implicitly deleted because the default definition would be ill-formed:
[build]        constexpr pair(const pair&) = default;
[build]                  ^~~~
[build] /usr/include/c++/8/bits/stl_pair.h:303:17: error: use of deleted function ‘FieldNo::FieldNo(const libtraco::FieldNo&)’

I know the errors are related due to the missing copy constructor. 我知道错误是由于缺少副本构造函数而引起的。 But why does it even try to copy things? 但是,为什么还要尝试复制内容呢? FieldNo('0', '5') in std::make_pair is clearly a rvalue . std::make_pair FieldNo('0', '5')显然是一个rvalue Am I missing something? 我想念什么吗?

Thanks! 谢谢!

EDIT: Minimal reproducible example added 编辑:添加了最小的可复制示例

#include <unordered_map>

struct FieldNo
{
    FieldNo() : a('0'), b('0') {}
    FieldNo(char a_, char b_) : a(a_), b(b_) {}
    // copy construction and assigment not allowed
    FieldNo(const FieldNo& other) = delete;
    FieldNo& operator=(const FieldNo& other) = delete;
    // move construction and assignment ok
    FieldNo(FieldNo&& other) = default;
    FieldNo& operator=(FieldNo&& other) = default;

    bool operator==(const FieldNo& lhs) const
    {
        return a == lhs.a && b == lhs.b;
    }

    char a;
    char b;
};

template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
    std::hash<T> hasher;
    seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}

struct FieldNoHasher 
{
    std::size_t operator()(const FieldNo& input) const
    {
        std::size_t seed = 0;
        hash_combine(seed, input.a);
        hash_combine(seed, input.b);
        return seed;
    }
};

enum class Members : int8_t
{
    FOO,
    BAR
};

typedef std::unordered_map<FieldNo, Members, FieldNoHasher> MyMapT;

const MyMapT& map()
{
   static const MyMapT fields = 
   {
       std::make_pair(FieldNo('0', '5'), Members::FOO),
       std::make_pair(FieldNo('1', 'X'), Members::BAR)
   };

   return fields;
}

int main()
{
    map();
}

Here's a minimal reproducible example: 这是一个最小的可重现示例:

#include <unordered_map>
#include <utility>

class C {
public:
    C() = default;
    C(const C&) = delete;
    C& operator=(const C&) = delete;
    C(C&&) = default;
    C& operator=(C&&) = default;
};

bool operator==(const C&, const C&)
{
    return true;
}

struct Hash {
    constexpr std::size_t operator()(const C&) const
    {
        return 42;
    }
};

int main()
{
    std::unordered_map<C, int, Hash> map {
        std::make_pair(C{}, 0)
    };
}

( live demo ) 现场演示

The problem is that you are calling the initializer_list constructor. 问题在于您正在调用initializer_list构造函数。 Because of the way initializer_list works, the underlying elements of an initializer_list are const , meaning the elements can only be copied, not moved. 由于的方式initializer_list的作品,一个的底层元素initializer_listconst ,这意味着元素只能被复制,不移动。 You cannot use the initializer_list constructor if your type is move only. 如果您的类型是仅移动,则不能使用initializer_list构造函数。 You have to use the other facilities: 您必须使用其他设施:

std::unordered_map<C, int, Hash> map;
map.emplace(C{}, 0);

or you can replace initializer_list with another container that supports moving (a vector, for example): 或者,您也可以用另一个支持移动的容器(例如,向量)替换initializer_list

std::vector<std::pair<const C, int>> values {
    std::make_pair(C{}, 0)
};
std::unordered_map<C, int, Hash> map(values.cbegin(), values.cend());

( live demo ) 现场演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用std :: pair作为键创建std :: unordered_map - Creating an std::unordered_map with an std::pair as key 使用std :: pair作为std :: unordered_map中的键 - Using std::pair as key in std::unordered_map std :: move with std :: make_pair - std::move with std::make_pair 使用带有std :: pair枚举类的unordered_map作为键的不完整类型struct std :: hash无效 - Invalid use of incomplete type struct std::hash with unordered_map with std::pair of enum class as key emplace(std :: move(key),std :: move(value))vs emplace(std :: make_pair(key,value)) - emplace(std::move(key), std::move(value)) vs emplace(std::make_pair(key, value)) std :: unordered_map :: emplace行为,没有移动/复制构造函数 - std::unordered_map::emplace behavior with no move/copy constructor `std :: pair``second`具有&#39;unordered_map`树的不完整类型 - `std::pair` `second` has incomplete type with `unordered_map` tree std::make_pair 与 std::pair 的构造函数的目的是什么? - What is the purpose of std::make_pair vs the constructor of std::pair? 为什么std :: map接受std :: pair作为键,但std :: unordered_map不接受? - Why does std::map accept a std::pair as key, but std::unordered_map does not? Multimap插入键typeinfo与std :: make_pair vs std :: pair构造函数 - Multimap insert key typeinfo with std::make_pair vs std::pair constructor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM