C++ 修改C+中std::unordered#u映射元素的值+;

C++ 修改C+中std::unordered#u映射元素的值+;,c++,c++11,reference,stl,unordered-map,C++,C++11,Reference,Stl,Unordered Map,我有以下问题。我有一个std::unordered_map,其中包含一个对象作为值。现在我想修改以前插入的对象 class Point { public: Point(float _x, float _y) : x(_x), y(_y) {} float x; float y; }; std::无序地图点; // ... 给它添加一些值。。。 点[1]。x=20.f;//错误 我得到一个奇怪的长编译错误,关于无法默认构造点。我的理解是,operator[]返回对映射

我有以下问题。我有一个
std::unordered_map
,其中包含一个对象作为值。现在我想修改以前插入的对象

class Point
{
public:
    Point(float _x, float _y) : x(_x), y(_y) {}

    float x;
    float y;
};
std::无序地图点;
// ... 给它添加一些值。。。
点[1]。x=20.f;//错误

我得到一个奇怪的长编译错误,关于无法默认构造点。我的理解是,
operator[]
返回对映射类型(也称为值)的引用,那么为什么我不能修改它呢?

如果键不在映射中,则需要
operator[]
来创建一个。表情

points[1]
需要能够在查找失败的情况下默认插入
(无论是否发生过查找失败-这是编译时要求,而不是运行时检查)。
无法满足该要求,因为
不是默认可构造的。因此出现了编译错误。如果要使用
无序映射::运算符[]
,则需要添加默认构造函数

如果默认构造的
对您的使用没有意义,那么您就不能使用
操作符[]
,并且必须在整个过程中使用
查找
(或者
at()
,如果您对例外情况没有异议):

如果给定键不存在元素,则就地构造映射类型的对象。在具有,
运算符[]
的映射中,要求映射类型为。更一般地说,映射类型必须是

简单的解决方案是向类中添加默认构造函数

Point() : Point(0.f, 0.f) {}
如果不可能,则必须使用其他函数来访问地图元素

要访问现有映射对象,可以使用,如果给定键不存在任何元素,则会引发异常

points.at(1).x = 20.f;
或者,您可以使用,它将迭代器返回到具有给定键的元素,或者返回到映射中最后一个元素后面的元素(请参阅),如果不存在这样的元素

auto it = points.find(1);
if (it != points.end())
{
    it->second = 20.f;
}

运算符[]
不能在
映射
无序映射
上使用,除非数据是默认可构造的。这是因为如果找不到对象,它将通过默认构造创建它

简单的解决方案是使您的类型默认可构造

如果没有:

template<class M, class K, class F>
bool access_element( M& m, K const& k, F&& f ) {
  auto it = m.find(k);
  if (it == m.end())
    return false;
  std::forward<F>(f)(it->second);
  return true;
}
模板
布尔访问元素(M&M、K常量和K、F&F){
自动it=m.find(k);
如果(it==m.end())
返回false;
标准:前进(f)(it->秒);
返回true;
}
然后:

std::无序地图点;
安置点(1,点(10.f,10.f));
访问元素(点,1,[](点和元素){
元素x=20.f;
});
将执行
点[1]的操作。x=20.f不存在异常代码风险,也不必使
默认可构造


这种模式——在这里我们传递一个函数来改变/访问容器中的一个元素——从Haskell monad design中窃取了一个页面。我会让它返回
可选
而不是
bool
,其中
X
是传入函数的返回类型,但这有点过分。

我想你需要
Point
类的默认构造函数,所以添加
Point():X(0),y(0){}
因此,对于不带参数的ctor,您可以使用
emplace
来避免使用
std::make_pair
。您还需要使用
点。在(1)
而不是
点[1]
进行访问。实际找不到点并不是导致错误的原因。它可能会失败,这会导致编译器在失败的地方编写代码,从而导致编译时错误。这意味着下一个酸橙,
点[1].x
也将导致错误,尽管有任何
点。插入您首先做的事情。简而言之,
[]
将无法处理无法默认构造的类型。@Yakk不认为我是在暗示它可以。更好的措辞?@Barry当然,但这意味着你没有解决OP的问题。下一行再次使用
[]
修改元素。我猜OP试图编写一个MCVE,但没有注意到MCVE的早期部分生成了相同的错误,而不是所讨论的行。在文本中,OP显然关注
点[1].x
行。@Yakk公平点。专注于答案,完全放弃了关于插入的部分。
auto it = points.find(1);
if (it != points.end())
{
    it->second = 20.f;
}
template<class M, class K, class F>
bool access_element( M& m, K const& k, F&& f ) {
  auto it = m.find(k);
  if (it == m.end())
    return false;
  std::forward<F>(f)(it->second);
  return true;
}
std::unordered_map<int, Point> points;
points.emplace(1, Point(10.f, 10.f));
access_element(points, 1, [](Point& elem){
  elem.x = 20.f;
});