gpt4 book ai didi

c++ - 我怎样才能分离运算符(operator) [] 上的获取和设置访问权限?

转载 作者:行者123 更新时间:2023-11-28 07:01:49 25 4
gpt4 key购买 nike

编辑 我通过引用右值引起了一些困惑。我在底部提供了一个我想做什么的例子。

我想把这两个调用分开:

obj[key] = value;
value = obj[key];

我尝试使用两个 operator[] 重载,希望 const 方法专用于右值,而非 const 版本专用于左值调用。

const ValueType& operator[] (const KeyType& key) const;
ValueType& operator[] (const KeyType& key);

但是我的 const 版本只有在 this 是 const 时才被调用。

我尝试使用一个包装器来覆盖 op=op ValueType

BoundValue<KeyType, ValueType> operator[] (const KeyType& key)

// later in BoundValue
operator ValueType() const
const V& operator= (const V& value)

这非常有效......直到我希望 op[] 会隐式转换为模板参数推导(这是不允许的)。

// example failure of wrapper
// ValueType is string, std::operator<< from string is a template method
cout << obj[key];

对于这种特定情况,我可以定义自己的 ostream 方法。

ostream& operator<< (ostream& os, const BoundValue<K, V>& bv);

但我的类型在任何用户定义的模板参数中同样会失败(似乎很可能)。

我可以想到两种解决方法,这两种方法都大大降低了我试图提供的语法糖的甜度:

// example where ValueType is string
cout << static_cast<string>(obj[key]);

或者,

// added to BoundValue
const ValueType& Cast() const

// later in use
cout << obj[key].Cast();

示例所需用例

Map<int, string> m;
m[1] = "one";

try
{
string one = m[1];
cout << "one is set: " << one << endl;
string two = m[2];
cout << "two is set: " << two << endl;
}
catch (...)
{
cout << "An exception was thrown" << endl;
}

预期输出:

one is set: one
An exception was thrown

异常是如何/为什么抛出的?我可以检查 key 是否存在,如果不存在则抛出。如果我不能将 get 与 set 分开,我不知道何时允许访问 key 。

最佳答案

operator[]返回一个实现解引用(get)和变异(set)操作的引用(类似)类型,operator*()operator=() .至少在理论上,您不需要返回真正的引用,只要您愿意做使返回的值(大部分)像引用一样的工作。所以你可以使用一个类型来存储一个指向 pair<const Key, Val> 的指针。在 map 中存在键和不存在的拷贝的情况下 Key否则。在后一种情况下,取消引用运算符会抛出异常,而变异运算符会将键移动到映射中。

保留 key 的拷贝以便在必要时将它们懒惰地添加到 map 中有点昂贵,但如果您真的想要该功能,则不一定离谱。一种可能的优化是始终将键添加到映射中,但不构建匹配的 Val。类型,也不允许 map返回 Key值(value)。一种简单的实现方法是为每个键值对分配一个位,指示键是否确实在映射中。和以前一样,尝试取消引用指向不在映射中的键值对的指针会引发异常,而值的变化只会构造新值并设置有效位。引用运算符的析构函数实际上会从映射中删除无效键,但假设此操作很少发生,因为根据定义,它是异常的。不幸的是,一个健壮的实现并不是那么简单,因为您需要考虑同时存在多个引用对象对应于同一个不存在的键的可能性。如果值类型足够大以至于可以在其上覆盖引用计数,那么引用计数方案是可能的,但我认为您需要担心数据竞争,除非您的 operator[]被仔细记录。 (引用计数并不是微不足道的,因为其中一个引用发生变化可能导致键变得有效。幸运的是,不需要维护有效键的计数,所以析构函数只需要在减少引用计数和/或删除无效 key 之前检查有效性。)

上述方法有几个弱点。一是 C++ 没有单一的变异运算符;它实际上有很多种( +=-=<<= 等等,还有不要忘记 ++-- )。所以会有相当多的样板文件。

更严重的是,程序保留 operator[] 返回的值是完全合法的作为引用对象,许多程序员会假设返回的引用是一个简单的 Val& .通常,此类代码的目的是能够在不执行多次查找的情况下执行多个突变。除了类型问题,这些天很容易解决 auto ,这“可能会奏效”,但延迟插入可能会带来一些惊喜。

关于c++ - 我怎样才能分离运算符(operator) [] 上的获取和设置访问权限?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22339759/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com