【问题标题】:How to provide const interface with iterators to a collection?如何为集合提供带有迭代器的 const 接口?
【发布时间】:2013-01-12 08:00:35
【问题描述】:

我想创建一个带有这样签名的函数:

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

但我也想在 map 和 iterator 不是 const 的情况下调用它,以便我可以修改找到的值:

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

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

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

void someFunction(const int &arg);

int notConstArg = 0;
someFunction(nonConstArg);

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

【问题讨论】:

  • 1) 您是否有理由不简单地返回迭代器? (虽然我很欣赏这不会解决这个问题)2)您的int 示例将无法修改底层int...
  • 我澄清了问题以说明原因。我返回一个布尔值,当它为假时,不能保证迭代器是有效的。换句话说,如果返回值为 false,则可能会跳过迭代器的计算。
  • 我不喜欢使用 end() 而不是 false 的部分是我必须构造一个虚拟映射来获取 end() 因为我真的有一个两级映射: map> 所以返回是内部映射的迭代器,但外部查找可能会失败,但要返回 end,我必须构造一个虚拟内部映射来为其获取 end()。除非有更好的方法来获取 end()?
  • 实际上,即使使用指针(const char *& 与 char *&),也无法摆脱这种 const/non const

标签: c++ templates stl iterator constants


【解决方案1】:

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

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&amp;map&amp;const map&amp;

【讨论】:

    【解决方案2】:

    不,我认为没有重载/模板魔法你不能做到这一点。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-11
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      相关资源
      最近更新 更多