2011-10-20 10 views
11

私は現在、いくつかのテンプレートメタプログラミングを行っています。私の場合、私は任意の "反復可能な"型、すなわちtypedef foo const_iteratorが同じ方法で存在する任意の型を扱うことができます。私はこれに新しいC++ 11テンプレートメタプログラミングを使用しようとしていましたが、特定の型が見つからないかどうかを検出する方法が見つかりませんでした。コンパイル時にtypedefを検出する(テンプレートメタプログラミング)

他の特性に基づいて他のテンプレートの特殊化をオン/オフする必要があるため、現在2つのパラメータを持つテンプレートを使用しています.2つ目はstd::enable_ifで生成されます。ここで私は現在やっているものです:

template <typename T, typename Enable = void> 
struct Foo{}; // default case is invalid 

template <typename T> 
struct Foo< T, typename std::enable_if<std::is_fundamental<T>::value>::type>{ 
    void do_stuff(){ ... } 
}; 

template<typename T> 
struct exists{ 
    static const bool value = true; 
}; 

template<typename T> 
struct Foo<T, typename std::enable_if<exists< typename T::const_iterator >::value >::type> { 
    void do_stuff(){ ... } 
}; 

私はexistsヘルパーテンプレートせずにこのような何かを行うことができませんでした。たとえば、この特殊化を使用する必要がある場合、無効なデフォルトのケースがインスタンス化されたため、単に

template<typename T> 
struct Foo<T, typename T::const_iterator> { 
    void do_stuff(){ ... } 
}; 

が機能しませんでした。

しかし、このexistsは新しいC++ 11標準のどこにも見つかりませんでした。私が知っている限り、この種のものはboost::type_traitsから取っています。しかし、のboost::type_traitsには、代わりに使用できるものは何も表示されていません。

この機能が欠落しているか、目的の動作を達成するための他の明白な方法を見落としましたか?

答えて

13

指定したタイプにconst_iteratorが含まれている場合は、単純にversio nのコード:

template<typename T> 
struct void_ { typedef void type; }; 

template<typename T, typename = void> 
struct Foo {}; 

template<typename T> 
struct Foo <T, typename void_<typename T::const_iterator>::type> { 
     void do_stuff(){ ... } 
}; 

このテクニックの仕組みについては、this answerを参照してください。

+3

これは、あなたの質問へのリンクを投稿する必要があります。 :)また、あなたはこれを好きに思っているようですが、あなたはそれを複数回提案しています。 – Xeo

+0

@ Xeo、はいこれはかなり簡単で簡単です。しかし、私はあなたの最初の部分を取得していない 'あなたは多分この1つの作品のあなたの質問へのリンクを投稿する必要があります。' :)あなたは答えている間私は私の以前の質問(コードそれ自体)?私はそれが推奨されていないと思う。 – iammilind

+1

Nono、私が言ったのは、あなたが[あなたの質問にどのように尋ねたところであなたの質問へのリンクを投稿する]ことです(http://stackoverflow.com/questions/6543652/different-template-syntax-for-finding-if-argument)。 -is-a-class-or-not)、それは最初は本当に明白ではないからです。 Woops、そして私はちょうど私が「質問」を書いたことを指摘しました。 – Xeo

7

ブール値を提供する形質has_const_iteratorを作成し、それを特殊化で使用することができます。

template <typename T> 
struct has_const_iterator { 
private: 
    template <typename T1> 
    static typename T1::const_iterator test(int); 
    template <typename> 
    static void test(...); 
public: 
    enum { value = !std::is_void<decltype(test<T>(0))>::value }; 
}; 

をそして、あなたは次のように特化することができます:このような

何かがそれを行う可能性があります

template <typename T, 
      bool IsFundamental = std::is_fundamental<T>::value, 
      bool HasConstIterator = has_const_iterator<T>::value> 
struct Foo; // default case is invalid, so no definition! 

template <typename T> 
struct Foo< T, true, false>{ 
    void do_stuff(){// bla } 
}; 

template<typename T> 
struct Foo<T, false, true> { 
    void do_stuff(){//bla} 
}; 
+1

:私たちは、その後const_iteratorタイプがこのようなis_iterator特性と一致していることを確認するためにhas_const_iterator形質を定義することができ

TICK_TRAIT(is_iterator, std::is_copy_constructible<_>) { template<class I> auto require(I&& i) -> valid< decltype(*i), decltype(++i) >; }; 

:だから私たちはこのような単純なis_iterator形質を定義すると言います'test()'の代わりに 'test(int)'を使用していますか?ありがとう! – nknight

+2

@nknight:理由: 'test'の呼び出しを明白にする。 – erenon

4

は、ここでメンバーの型特性チェックの別のバージョンです:

template<typename T> 
struct has_const_iterator 
{ 
private: 
    typedef char      yes; 
    typedef struct { char array[2]; } no; 

    template<typename C> static yes test(typename C::const_iterator*); 
    template<typename C> static no test(...); 
public: 
    static const bool value = sizeof(test<T>(0)) == sizeof(yes); 
}; 
1

これを行うにはいくつかの方法があります。また

TICK_TRAIT(has_const_iterator) 
{ 
    template<class T> 
    auto require(const T&) -> valid< 
     has_type<typename T::const_iterator> 
    >; 
}; 

template <typename T, typename Enable = void> 
struct Foo; 

template <typename T> 
struct Foo< T, TICK_CLASS_REQUIRES(std::is_fundamental<T>::value)>{ 
    void do_stuff(){ ... } 
}; 

template<typename T> 
struct Foo<T, TICK_CLASS_REQUIRES(has_const_iterator<T>())> { 
    void do_stuff(){ ... } 
}; 

:あなたはこのようTickを使用することができ、C++ 11では

BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator); 

template <typename T, typename Enable = void> 
struct Foo; 

template <typename T> 
struct Foo< T, typename boost::enable_if<boost::is_fundamental<T> >::type>{ 
    void do_stuff(){ ... } 
}; 

template<typename T> 
struct Foo<T, typename boost::enable_if<has_const_iterator<T> >::type> { 
    void do_stuff(){ ... } 
}; 

:C++ 03では、特性(docssource)を定義するために、ブーストとenable_ifを使用することができますTickを使用すると、実際にはconst_iteratorが実際にイテレータであることを実際に検出するために、特性をさらに向上させることができます。あなたは `選んだ理由がある

TICK_TRAIT(has_const_iterator) 
{ 
    template<class T> 
    auto require(const T&) -> valid< 
     has_type<typename T::const_iterator, is_iterator<_>> 
    >; 
};