我提出了以下代码,该代码演示了一种在STL集合上进行一般迭代并获取密钥值的技术,无论密钥是如何存储的。
这个的上下文是我重构两个函数,它们在两个集合上运行相同的功能:一个是set<int>
,另一个是map<int, int>
所以在第一种情况下我想要在*it
上行动,在it->first
上行动(其中it
是const_iterator。)
重要的是,我想这样做,因为集合非常大,我不想只是从set
创建一个map
,所以我只能处理一个特定的类型
#include <map>
#include <set>
#include <iostream>
using namespace std;
// General case for obtaining from, say, a set.
template< typename T >
const typename T::key_type getKey( const typename T::const_iterator& it )
{
return *it;
}
// Specific case for a map<int,int>
template<>
const map<int, int>::key_type getKey< map<int, int> >( const map<int, int>::const_iterator& it )
{
return it->first;
}
template< typename T >
void dumpOut( T& coll )
{
for ( typename T::const_iterator it = coll.begin(); it != coll.end(); ++it )
{
const typename T::key_type& a = getKey<T>(it);
cout << a << endl;
}
}
int main()
{
set<int> s1;
s1.insert(10);
s1.insert(15);
s1.insert(20);
dumpOut< set<int> >( s1 );
map<int, int> m1;
m1.insert( pair<int, int>(11, -1) );
m1.insert( pair<int, int>(16, -1) );
m1.insert( pair<int, int>(21, -1) );
dumpOut< map<int, int> >( m1 );
return 0;
}
我的问题是:是否有可能使map<int,int>
的专业案例更加通用,因为无论关键和值实际是什么,这种方法通常都会明确地适用于map
。< / p>
任何指针(没有双关语)都会有用。请注意,我不能使用C ++ 11解决方案,尽管我对从学术角度使用它的解决方案感兴趣。感谢。
答案 0 :(得分:2)
这里有一个C ++语言问题 - 不允许对函数进行部分特化。 所以它不能这么简单:
// Specific case for a map<int,***>
template<typename Value_, typename Comp_, typename Alloc_>
const typename map<int, Value_, Comp_, Alloc_>::key_type getKey< map<int, Value_, Comp_, Alloc_> >( const typename map<int, Value_, Comp_, Alloc_>::const_iterator& it )
{
return it->first;
}
幸运的是,允许对类进行部分特化 - 所以改为这样:
// work - for let say - sets
template <class Type_>
struct Key {
Key(typename Type_::const_iterator it) : value(*it) {}
typename Type_::key_type value;
};
// work - for map<***>
template <class Key_, class Value_, class Comp_, class Alloc_>
struct Key<map<Key_, Value_,Comp_,Alloc_> > {
typedef map<Key_, Value_,Comp_,Alloc_> Type_;
Key(typename Type_::const_iterator it) : value(it->first) {}
typename Type_::key_type value;
};
template< typename T >
const typename T::key_type getKey( const typename T::const_iterator& it )
{
return Key<T>(it).value;
}
我在那里复制了您更改的示例:http://ideone.com/tE2aC
答案 1 :(得分:1)
您需要定义可以在外部定义的特征。您还希望它尝试提取key_type,如果存在,则adn属于defautl情况(如果不存在)(默认情况可以在以后专用)。这需要快速捕捉SFINAE和模板魔法:
//// This is a SFINAE context enabler. If T is defined R is returned
template<class T, class R=void> struct enable_if_type
{
typedef R type;
};
//// Default case is undefined as you want to get an error if you try to get a key_type from something that has none
template<class T, class Enable=void> struct key_type_of;
//// If T::key_type is a valid expression, extract it
template<class T>
struct key_type_of< T
, typename enable_if_type< typename T::key_type>::type
>
{
typedef typename T::key_type type;
};
现在任何带有key_type typedef的类型都会使用它,其他不会编译但你可以使用 key_type_of的专业化,为其提供成功的匹配。
示例:
完成此操作后,您实际上可以使用它来获取key_type。要以独立于容器的方式提取密钥本身,您可以创建一个外部key_of函数,您可以为广泛的集合类型进行推广。