How to provide const interface with iterators to a collection?

匆匆过客 提交于 2020-01-14 13:42:11

问题


I would like to create a function with a signature like this:

// 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);

But I would like to also call it in cases where the map and iterator are not const so that I can modify the found value:

const Key key;
std::map<Key, Value> map;
std::map<Key, Value>::iterator found;

if (lookup(key, map, found)) {
  found->second.modifingNonConstFunction()
}

But I do not believe I can pass a std::map<Key, Value>::iterator object to a function expecting a reference to a std::map<Key, Value>::const_iterator since they are different types, whereas I normally could if the const was part of C++ declaration of the type like this and I could promote the non-const type to a const type:

void someFunction(const int &arg);

int notConstArg = 0;
someFunction(nonConstArg);

Other than by using templates to provide two definitions for lookup(), one as shown with const arguments 2 and 3 and another with non-const arguments 2 and 3, is there a better way in C++ to accomplish this more akin to how const int & can be passed a non-const int in the example above. In other words, can I just have a single function and not two?


回答1:


No, I don't think you can do this without overloads/template magic.

The compiler is protecting you from the following scenario:

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!
}



回答2:


If the function is simple or you don't mind binary bloat, just make every parameter a template parameter.

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';
}

This works since T can be both, map and const map so T& is map& or const map&.



来源:https://stackoverflow.com/questions/14571221/how-to-provide-const-interface-with-iterators-to-a-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!