无法在 unordered_map 个引用中插入非常量值

Can't insert non-const value in unordered_map of references

我正在尝试创建 2 个 std::unordered_map,一个包含 ,第二个包含 。 如果你好奇的话,我会在最后解释为什么我想这样做。

我的问题是 k_i 具有类型 std::reference_wrapper 的值,k_i.insert 不起作用。但是,如果我使 k_i 具有值 std::reference_wrapper<const A>,则插入有效。

我只是想不通这是为什么,我很好奇。

<<<<<编辑: 问题是找到 returns std::pair<const Ket, T>
所述 Eljay 在评论中。因此,第二个 std::unordered_map 需要具有值 const。 <<<<<

代码: 编译器:g++ 版本 10.1 编译标志:-Wall -Wextra -std=c++20

#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>

class A {
public:
  A(const int x) : x(x) {
    std::cout << "A::A(const int x) : x(" << x << ")\n";
  }

  A(const A& a) {
    std::cout << "A::A {" << x << "} (const A& a {" << a.x << "} )\n";
    x = a.x;
  }

  A(A&& a) {
    std::cout << "A::A {" << x << "} (A&& a {" << a.x << "} )\n";
    x = a.x;
  }

  A& operator=(const A& a) {
    std::cout << "A::operator= {" << x << "} (const A& a)\n";
    x = a.x;
    return *this;
  }

  A& operator=(A&& a) {
    std::cout << "A::operator= {" << x << "} (A&& a)\n";
    x = a.x;
    return *this;
  }

  ~A() {
    std::cout << "A::~A(" << x << ")\n";
  }

    friend std::ostream& operator<<(std::ostream& os, const A& dt);

  int x;
};

std::ostream& operator<<(std::ostream& os, const A& dt) {
    return os << dt.x;
}

template <typename K, typename V, typename... args>
void print_um(const std::unordered_map<K, V, args...> &umap) {
    for (const auto &[x, y] : umap) {
        std::cout << "(" << x << "," << std::ref(y).get() << "); ";
    }
    std::cout << "\n";
}

template <typename T>
struct MyHash {
    std::size_t operator()(T const& s) const noexcept {
        return std::hash<int>{}(std::ref(s).get());
    }
};

template <typename T>
struct MyEquals {
    constexpr bool operator()(const T &lhs, const T &rhs) const {
        return lhs == rhs;
    }
};

struct MyHash_A {
    std::size_t operator()(A const& s) const noexcept {
        return std::hash<int>{}(s.x);
    }
};

struct MyEquals_A {
    constexpr bool operator()(const A &lhs, const A &rhs) const {
        return lhs.x == rhs.x;
    }
};

int main() {

    std::unordered_map<A, int, MyHash_A, MyEquals_A> k_s;
    std::unordered_map<std::reference_wrapper<int>, std::reference_wrapper<const A>, MyHash<std::reference_wrapper<int>>, MyEquals<std::reference_wrapper<int>>> k_i;
{
    A a(5);
    std::cout << "1----\n";
    k_s[a] = 12;
    std::cout << "2----\n";
}
    std::cout << "3----\n";
    print_um<>(k_s);


    std::cout << "4----\n";
    A a(5);
    std::cout << "5----\n";
    auto it = k_s.find(a);
    std::cout << "6----\n";
    k_i.emplace((*it).second, (*it).first);
    // // k_i[(*it).second] = ref_name;


    std::cout << "7----\n";
    print_um<>(k_s);
    std::cout << "8----\n";
    print_um<>(k_i);

    std::cout << "9----\n";
    int x = 12;
    int &ref = x;
    auto is_there = k_i.find(ref);
    if (is_there != k_i.end()) {
        std::cout << "elem: " << (*is_there).second.get() << "\n";
    } else {
        std::cout << "why? :(\n";
    }
    std::cout << "10---\n";
    return 0;
}

至于为什么我创建这段代码,我想能够通过值或键互换地访问一些数据(是否有更好的数据结构?)。就像用户名和令牌一样,有时我有一个,有时我有另一个,并且使用引用确保我不会浪费 space。 Ofc,如果必须更改一个值,我会因为密钥而使 unordered_map 中的存储桶位置无效,但我会在以后处理该问题。另一个动机是学习更多的 C++ 并测试它的极限(或我的极限)。

来自 UnorderedAssociativeContainer requirements:

For std::unordered_map and std::unordered_multimap the value type is std::pair<const Key, T>.

在您的代码中 k_sunordered_map<A, int>,因此值类型是 pair<const A, int>。在这里:

auto it = k_s.find(a);

你得到一个指向这样一对的“指针”,(*it).first 的类型是 const A

您的 k_iunordered_map<..., ref<A>>,当您在此处插入时:

k_i.emplace(..., (*it).first);

您实际上是在尝试用 const A 初始化 ref<A>,这显然行不通。

当您将 k_i 类型更改为 unordered_map<..., ref<const A>> 时,您将 ref<const A> 初始化为 const A,这很好。

很多人在评论中提到Key type必须是const。然而,OP 似乎想知道为什么 k_i 中的值类型也需要是 const.

这是因为您正在引用 k_s 中的键,即 const A,您不能使用非常量引用来引用它。

要正确声明 k_s,您可能需要执行以下操作:

std::unordered_map<
    std::reference_wrapper<decltype(k_s)::value_type::second_type>, 
    std::reference_wrapper<decltype(k_s)::value_type::first_type>,
    yourHash, yourComp
> k_s;

您的一个替代解决方案是使用另一个实际支持双向查找的容器,例如 Boost.Bimap.