如何为集合提供带有迭代器的 const 接口

How to provide const interface with iterators to a collection?

本文关键字:迭代器 const 接口 集合      更新时间:2023-10-16

我想创建一个带有如下签名的函数:

// Set found to be an iterator to the location of key in map or end()
// if not found.
bool lookup(const Key &key,
            const std::map<Key, Value> &map,
            std::map<Key, Value>::const_iterator &found);

但是我也想在映射和迭代器不是常量的情况下调用它,以便我可以修改找到的值:

const Key key;
std::map<Key, Value> map;
std::map<Key, Value>::iterator found;
if (lookup(key, map, found)) {
  found->second.modifingNonConstFunction()
}

但是我不相信我可以将std::map<Key, Value>::iterator对象传递给期望引用std::map<Key, Value>::const_iterator的函数,因为它们是不同的类型,而如果const是C++声明的一部分,我通常可以这样做,这样我就可以,我可以将非 const 类型提升为 const 类型:

void someFunction(const int &arg);
int notConstArg = 0;
someFunction(nonConstArg);

除了使用模板为lookup()提供两个定义之外,一个如参数 2 和 3 所示const另一个如非常量参数 2 和 3 所示,是否有更好的C++方法来实现这一点,更类似于如何在上面的例子中传递const int &非常量int。 换句话说,我可以只有一个函数而不是两个吗?

如果函数很简单,或者您不介意二进制膨胀,只需将每个参数都设置为模板参数即可。

template <typename Key, typename T, typename Iter>
bool lookup(Key const& key,
            T& map,
            Iter &found)
{
  return (found=map.find(key))!=map.end();
}
int main()
{
  std::map<std::string, int> m; m["hello"] = 42;
  std::map<std::string, int> const cm(m.begin(), m.end());
  std::map<std::string, int>::iterator it;
  std::map<std::string, int>::const_iterator cit;
  std::cout << std::boolalpha << lookup("hello", m, it) << 'n'; // Key isn't even std::string
  std::cout << std::boolalpha << lookup("hello", m, cit) << 'n';
  //std::cout << std::boolalpha << lookup("hello", cm, it) << 'n'; // error
  std::cout << std::boolalpha << lookup("hello", cm, cit) << 'n';
}

这是有效的,因为T可以是mapconst map,所以T&map&const map&

不,我认为如果没有重载/模板魔法,您将无法做到这一点。

编译器可保护您免受以下情况的影响:

typedef vector<int> T;
const T v;  // Can't touch me
void foo(T::const_iterator &it) {
    it = v.begin();  // v.begin() really is a const_iterator
}
int main() {
    T::iterator it;
    foo(it);
    *it = 5;   // Uh-oh, you touched me!
}