2012-05-25 11 views
6

ノンタイプのテンプレートパラメータと非タイプのテンプレート引数を持つテンプレートにタイプを解体できるテンプレートを作成したいと思います。たとえばArray<5>template<int> Array5に分解しますが、どのタイプの非型テンプレートパラメータ(整数型、ポインタ、メンバーポインタなど)でも一般的に機能します。ノンタイプのテンプレートパラメータのタイプの概要

テンプレートの特殊化との最初の試み、:

template<typename T> struct foo { enum { n = 1 }; }; 

template<int x> struct bar { enum { n = x }; }; 

template<typename T, template<T> class X, T x> 
struct foo< X<x> > { enum { n = x }; }; // here x must be of integral type, but that's just for testing 

int main(int, char**) { return foo< bar<16> >::n; } 

クラン3.1は言う:

test145.cpp:6:8: warning: class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used 
struct foo< X<x> > { enum { n = x }; }; 
     ^~~~~~~~~~~ 
test145.cpp:5:19: note: non-deducible template parameter 'T'      
template<typename T, template<T> class X, T x> 
       ^
1 warning generated. 

第二には、関数テンプレートで、試してみてください。

template<typename T, T x> 
struct box 
{ 
    static constexpr T value() { return x; } 
}; 

template<typename T, template<T> class X, T x> 
box<T, x> foo(X<x>); 

template<int> struct asdf { }; 

int main(int, char**) { return decltype(foo(*(asdf<9>*)0))::value(); } 

クラン氏は述べています:

test150.cpp:12:41: error: no matching function for call to 'foo' 
int main(int, char**) { return decltype(foo(*(asdf<9>*)0))::value(); } 
             ^~~ 
test150.cpp:8:11: note: candidate template ignored: couldn't infer template argument 'T' 
box<T, x> foo(X<x>); 
     ^
1 error generated. 

GCC 4.7は同様のことを言います。

これは基本的な制限ですか?

ボーナスの質問:それがそうであれば、単純で汎用的なコードではなくても、有限のコードで無限の可能性をすべて処理する方法はありますか? (これは、例えばポインタでは困難で取得します:あなたは私はあなたがどちらかtemplate<T*>を書くことができないと思うtemplate<T>を書くように見えることはできません同じ理由で。)

私が求めている理由は聞かないでください。

+1

私は言う必要があります:あなたが必要とするものが分かりません –

+2

私は次のように要約することができます: 'テンプレート構造A {}'。'arg :: template_'が' template Array'であるようなテンプレート 'arg'を書くことは可能でしょうか(もしそうなら、どうすればよいでしょうか?)' arg :: type 'は' int'であり、 'arg' > :: value'は '5'(型は' int')であり、これを汎用的にして、可能なすべての非型テンプレート引数をこのように扱うことができます。 – reima

+0

それは基本的にそれです。私ができるよりもはっきりと置いてくれてありがとう! – glaebhoerl

答えて

2

この他の質問は基本的に同じことを求めているが、テンプレートタイプパラメータではなく、テンプレートは非タイプパラメータについて:タイプパラメータについてはtemplate metaprogramming: (trait for?) dissecting a specified template into types T<T2,T3 N,T4, ...>

、それは本当に簡単です。コードは次のようになります。

#include <tuple> 
#include <vector> 

template <class T> struct explode; 

template <template <class... Args> class T, class... N> 
struct explode<T<N...>> 
{ 
    typedef T<N...> type; 
    template <class... Args> using template_ = T<Args...>; 
    template <int I> using type_parameter = 
     typename std::tuple_element<I, std::tuple<N...>>::type; 
}; 

#if TESTING 
void test_harness() 
{ 
    typedef explode<std::vector<int>> exv; 

    exv::template_<char> vchar; // The second parameter still has its default argument! 
    exv::template_<exv::type_parameter<0>, exv::type_parameter<1>> vint; 

    static_assert(std::is_same<exv::template_<char>, std::vector<char>>::value, ""); 
    static_assert(std::is_same<decltype(vchar), std::vector<char>>::value, ""); 
    static_assert(std::is_same<decltype(vint), std::vector<int>>::value, ""); 
    static_assert(std::is_same<exv::type, std::vector<int>>::value, ""); 
    static_assert(std::is_same<exv::type_parameter<0>, int>::value, ""); 
    static_assert(std::is_same<exv::type_parameter<1>, std::allocator<int>>::value, ""); 
} 
#endif 

しかし、それはまだ可能かどう非タイプパラメータのために、私は考え出したていません。類似したコードで始めることができます。

template <class... ArgTypes, template <ArgTypes... Args> class T, ArgTypes... N> 
struct explode<T<N...>> 
{ 
    typedef T<N...> type; 
    template <ArgTypes... Args> using template_ = T<Args...>; 
    template <int I> using type_of_parameter = 
     typename std::tuple_element<I, std::tuple<ArgTypes...>>::type; 
    template <int I> struct nontype_parameter { 
     static constexpr type_of_parameter<I> value() { 
      return std::get<I>(std::tuple<ArgTypes...>(N...)); 
     } 
    }; 
}; 

} 、

test.cc:8:8: warning: class template partial specialization contains a template 
     parameter that can not be deduced; this partial specialization will never 
     be used 
struct explode<T<N...>> 
     ^~~~~~~~~~~~~~~~ 
test.cc:7:20: note: non-deducible template parameter 'ArgTypes' 
template <class... ArgTypes, template <ArgTypes... Args> class T, ArgTypes... N> 
       ^

、あなたはその問題を何とか離れて行かせた場合でも、あなたはまだ手コーディングconstexprバージョンでstd::getを交換する必要があるだろう:

が、クラン(少なくとも)は、それを受け入れませんなぜなら、標準ライブラリのstd::getconstexprではないからです。

+0

ええ、それは基本的に私が最初の例で遭遇したのと同じ問題です。テンプレートパラメータがテンプレートパラメータリストにのみ存在し、特殊化引数には存在しない場合は推論できません。おそらく標準ではこれを義務付けています。そうでないと、不可能なもののように見えないからです。 – glaebhoerl