2012-05-25 93 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

我相信可以總結如下:讓'template struct A {}'。是否有可能(如果是這樣,如何)寫一個模板'arg',使得'arg > :: template_'是'template Array','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::get不是constexpr

+0

是的,這與我的第一個例子遇到的基本相同。如果模板參數僅存在於模板參數列表中,但不存在於特化參數中,則無法推斷。據推測標準要求這樣做,因爲否則它看起來不可能是不可能的。 – glaebhoerl