模板 C++:如何访问 std::map 和 std::set 的迭代器值?
Template C++: How to access iterator value for both std::map and std::set?
我有一个特定的搜索功能。因为它在 std::set
和 std::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
地图),因此,将此程序移至模板函数并具有 MyFindFunctionInMap
和MyFindFunctionInSet
在调用搜索过程函数后处理迭代器到值转换的函数将无济于事。
PS: 抱歉,我正在使用 C++98..
您可以使用 boost::transform_iterator
从类似 map
的迭代器构建一个类似 set
的迭代器。
创建一个由类似 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;
}
此访问器依赖于键类型和值类型 distinct/same for map/set。
您可以使用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);
一个实用的解决方案是使用额外的布尔参数来确定容器是否为映射:
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
}
..
}
我有一个特定的搜索功能。因为它在 std::set
和 std::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
地图),因此,将此程序移至模板函数并具有 MyFindFunctionInMap
和MyFindFunctionInSet
在调用搜索过程函数后处理迭代器到值转换的函数将无济于事。
PS: 抱歉,我正在使用 C++98..
您可以使用 boost::transform_iterator
从类似 map
的迭代器构建一个类似 set
的迭代器。
创建一个由类似 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;
}
此访问器依赖于键类型和值类型 distinct/same for map/set。
您可以使用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);
一个实用的解决方案是使用额外的布尔参数来确定容器是否为映射:
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
}
..
}