使用常量键但非常量值进行映射
map with const keys but non const values?
我有一种情况,我想要一个不允许在初始化后添加/删除键的映射,但允许更改值(因此我不能简单地使映射const
(。即
/*semi-const*/ map<int,int> myMap = initMap();
myMap[1] = 2; // NOT OK, because potentially adds a new key
myMap.at(1) = 2; // OK, because works only if key is present
for (auto & element : myMap) {
element.second = 0; // OK, values may change
}
我可以为std::map
编写自己的包装器,但我感觉这并不少见,所以我想知道是否已经有现有的解决方案。
对于不允许添加/删除键的地图,是否有一些标准习惯用法,而值可能会更改?
ps:我知道标题本身有点模糊,因为键已经在地图上了,但我希望它清楚我的意思......
您能否创建一个包含值的包装器,该值允许在const
时发生突变,并将其放在map
中?像这样:
template<typename T>
class Mutable {
mutable T value;
public:
const Mutable& operator=(const T& v) const { value = v; return *this; }
T& get() const { return value; }
};
然后您的地图可以是类型
const std::map<int, Mutable<int>>
现场演示。
我通常认为这是一个陷阱,C++不仅仅是一个功能,但是,如果它适合你的应用程序,你可以只使用指针值。
#include <map>
#include <memory>
int main(int argc, char ** argv)
{
using namespace std;
const map<int, shared_ptr<int>> myMap = { {1, make_shared<int>(100)} };
// *(myMap[1]) = 2; // Does not compile
*(myMap.at(1)) = 2;
for (auto & element : myMap)
{
*(element.second) = 0;
}
return 0;
}
这实际上只是另一个答案的更简单版本(显然您可以根据需要在shared_ptr
/unique_ptr
之间进行选择(。
标准库中的容器是针对一种用法优化的类,这些类应按原样使用或包含在更高级别的类中。
在这里,您的要求(初始化后修复的密钥(不在标准库容器中,因此您必须构建自己的实现。由于它不会是std::map
,因此您可以仅实现所需的操作,可能仅此而已operator []
...
我知道您只是想禁用索引访问运算符,以便用户不会意外地将默认构造的项目添加到地图中。 我的解决方案受到克里斯·德鲁解决方案的启发,但具有保持常量正确的额外好处(即不允许在地图为常量时更改地图的值(。
实质上,通过禁用默认构造,您可以删除调用 std::map
提供的索引访问运算符的功能。 其他方法将保持可用,因为std::map
是一个类模板,并且在调用成员函数之前不会计算它们。 因此,std::map::at
可以正常工作,但std::map::operator[]
会导致编译时错误。
受 Chris 的启发,您可以在mapped_type上使用包装器来禁用默认构造。 我拿了他的演示并对其进行了一些调整,以演示如何禁用默认构造并将其与std::map
而不是const std::map
一起使用。
template<typename T>
class RemoveDefaultConstruction {
T value;
public:
RemoveDefaultConstruction() = delete; // The magic is here
RemoveDefaultConstruction(const RemoveDefaultConstruction &other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
RemoveDefaultConstruction(RemoveDefaultConstruction &&other) noexcept(std::is_nothrow_move_constructible<T>::value) = default;
RemoveDefaultConstruction(T &&t) noexcept(std::is_nothrow_constructible<T, decltype(std::forward<T>(t))>::value) :
value{std::forward<T>(t)} {
}
RemoveDefaultConstruction& operator=(const RemoveDefaultConstruction &other) = default;
RemoveDefaultConstruction& operator=(RemoveDefaultConstruction &&other) = default;
RemoveDefaultConstruction& operator=(T &&other) { value = std::move(other); return *this; }
RemoveDefaultConstruction& operator=(T const &other) { value = other; return *this; }
T const &get() const { return value; } // Keep const correctness
T &get() { return value; } // Keep const correctness
};
void update(std::map<int, RemoveDefaultConstruction<int>> &m, int k, int v) { m.at(k) = v; }
void update(std::map<int, RemoveDefaultConstruction<int>> const &m, int k, int v) {
//m.at(k) = v; // ERROR: Cannot change a const value
}
现场演示
我在这里看到 2 个选项
-
使地图常量并在更改某些内容时使用const_cast
const std::map myMap;
myMap[1] = 2;//不行,因为 const map
(const_cast&>(myMap((.at(1( = 2;//OK with const_cast
-
创建一个包装类或派生一个只读取和更新现有值方法的自定义映射
我认为没有一种内置的方法可以仅使用更新值制作地图,并限制和插入。
- 使用迭代器替换映射中的常量项的方法
- 将整型常量映射到类型
- 常量映射和常量元素映射之间的区别
- 如何常量映射变量
- 从另一个常量标准::映射初始化一个常量标准::映射的一部分
- 使用常量键但非常量值进行映射
- Swig:如何类型映射c ++字符串常量和python字符串?
- 将C++枚举映射为常量字符*
- 调用 size() 的常量映射<字符串,矢量<int>>导致错误
- 通过常量std::映射进行搜索
- 调整常量映射键
- 无法取消引用映射常量迭代器的mapped_type
- 如何将const_cast的const指针向量映射到非常量指针向量
- C++映射 - 表达式必须是整数常量表达式
- 静态常量 int 作为映射下标
- 从常量迭代器到映射向量,获取映射向量中映射元素的键和值
- C++常量,Boost无序映射,运算符[]
- 为什么只有非常量映射提供类似于关联数组的直接元素检索?
- 常量映射迭代器不会设置为 mymap.begin()
- 用于从常量映射中读取的惯用C++