2

次のコードを思いついたのは、STLコレクションを一般的に反復処理し、キーの格納方法に関係なくキー値を取得する手法を示しています。

これのコンテキストは、2つのコレクションで同じ機能を操作する2つの関数をリファクタリングしているということです。1つはaで、set<int>もう1つはmap<int, int>そうです。 )。*itit->firstit

重要なのは、コレクションが非常に大きいため、これを実行したいのです。特定のタイプを1つだけ処理できるように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

任意のポインタ(しゃれは意図されていません)が役立ちます。アカデミックな観点からC++11ソリューションに興味がありますが、C++11ソリューションは使用できませんのでご注意ください。ありがとう。

4

2 に答える 2

2

ここで1つの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

于 2012-06-29T12:44:30.470 に答える
1

外部で定義できる特性を定義する必要があります。また、存在する場合はkey_typeを抽出し、そうでない場合は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の特殊化を使用して、一致を成功させることができます。

例:

http://ideone.com/3PxJm

これが完了すると、実際にそれを使用してkey_typeを取得できます。コンテナーに依存しない方法でキー自体を抽出するために、幅広いタイプのコレクションに一般化できる外部key_of関数を作成できます。

于 2012-06-29T11:59:27.683 に答える