【问题标题】:Template C++: How to access iterator value for both std::map and std::set?模板 C++:如何访问 std::map 和 std::set 的迭代器值?
【发布时间】:2015-06-16 08:23:09
【问题描述】:

我有一个特定的搜索功能。因为std::setstd::map 都使用了它,所以它在我们的代码中被复制了(不使用模板)。

我必须维护这两个函数,并且我想使用模板将它们移动到一个函数中(然后只需要维护一个搜索程序)。

我找不到如何将迭代器转换为容器的value_type。对于std::set,您只需要取消引用迭代器(*iter),但对于std::map,您需要访问迭代器的第二项(它是一对)iter->second

这是一个孤立的例子:

template <class Container, class Object> bool MyFindFunction( const Container& container, Object& found )
{
    Container::const_iterator iter = container.begin();
    // do my special search procedure here
    // note that this code also needs to access the iterator's value...

    if ( iter != container.end() )
    {
        found = *iter; // this works for set, but not for map
        found = iter->second; // this works for map, but not for set
        // HOW TO MAKE IT WORK FOR BOTH??
        return true;
    }
    else
    {
        return false;
    }
}

int main ()
{
    std::set<double> mySet;
    std::map<int,double> myMap;
    double found = 0;

    MyFindFunction( mySet, found );
    MyFindFunction( myMap, found );
}

请注意,特殊搜索过程还需要访问 value_type(或 mapped_type 用于映射),因此,将此过程移动到模板函数并具有 MyFindFunctionInMapMyFindFunctionInSet 函数处理迭代器到值调用搜索程序函数后转换无济于事。

PS:对不起,我用的是 C++98..

【问题讨论】:

  • 只需使用模板化迭代器创建一个access 函数并为map/set 迭代器实现它。所以你没有完整的功能实现两次,只是有问题的访问
  • 迂腐点:std::map&lt;A, B&gt;value_typestd::pair&lt;const A, B&gt;,这正是解引用迭代器给你的。您要查找的类型是mapped_type
  • 是的,我正在寻找 mapped_type,它没有为集合定义...这个只有 value_type....

标签: c++ templates dictionary stl set


【解决方案1】:

您可以使用template function overload来区分这些情况:

template <typename V>
inline V get_value(const V& v) { return v; }
template <typename K, typename V>
inline V get_value(const std::pair<K, V>& p) { return p.second; }

然后

found = get_value(*iter);

LIVE DEMO

【讨论】:

  • 我喜欢这样,但它无法编译(我使用的是 VS2010)。显然编译器不使用地图版本功能。有没有办法传递 get_value 函数用作参数?
  • @jpo38 我的错。我已经更新了我的答案,请再次检查。
  • 它工作得很好,确实是解决问题的好方法。谢谢!
【解决方案2】:

您可以使用boost::transform_iteratormap-like 迭代器构建set-like 迭代器。

创建一个由类似set 的迭代器参数化的内部模板函数,并且只将迭代器而不是容器作为参数。将原始迭代器或转换后的迭代器分派给此函数。


编辑如果你不能使用 boost,构建一些仿函数来访问你的东西:

#include <map>
#include <set>
#include <iostream>


using namespace std;


template<class Key, class Value>
struct access_key
{
    template<class Ref>
    const Key &operator()(const Ref &v) const
    {
        return v.first;
    }
};

template<class Key>
struct access_key<Key, Key>
{
    template<class Ref>
    const Key &operator()(const Ref &v) const
    {
        return v;
    }
};


template<class Container>
void fn(Container t)
{
    access_key<typename Container::key_type, typename Container::value_type> a;
    cout << a(*t.begin()) << endl;
}


int main()
{
    set<int> s;
    s.insert(1);

    map<int, int> m;
    m[1] = 1;

    fn(s);
    fn(m);

    return 0;
}

此访问器依赖于 map/set 的键类型和值类型是不同/相同的。

【讨论】:

  • @jpo38 查看更新。将来,您可能想在问题中说明限制,顺便说一句。
  • 很抱歉。 access_key 运算符返回 v.first,它应该是 v.second 吗?你能提供一个关于如何使用这个 access_key 结构的例子吗?
  • 这可以访问键,而不是值,对吧?我适应了价值(将v.first更改为v.second并将值从Key返回到Value但它不起作用)
  • @jpos38 只需将first 更改为second。其余的保持不变。
【解决方案3】:

一个实用的解决方案是使用额外的布尔参数来确定容器是否是地图:

template <class Container, class Object> bool MyFindFunction( const Container& container, Object& found, bool isMap ){
   ..
   if(!isMap){
      found = *iter; // this works for set, but not for map
   }
   else{
      found = iter->second; // this works for map, but not for set
   }
..
}

【讨论】:

  • 这不起作用。即使仅与 isMap 设置为 true 一起使用,编译器也会抱怨 error C2440: '=' : cannot convert from 'const std::pair&lt;_Ty1,_Ty2&gt;' to 'double'
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 2014-05-27
  • 1970-01-01
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 2012-10-03
  • 2012-01-10
相关资源
最近更新 更多