2012-05-25 14 views
6

Vorrei scrivere un modello che può decostruire un tipo in un modello con parametri modello non di tipo insieme ai suoi argomenti modello non di tipo. Ad esempio, decomprimerebbe e, ma funzionerebbe in modo generico per qualsiasi tipo di parametro modello non di tipo (tipi interi, puntatori, puntatori membri, ecc.).Riassunto su tipi di parametri modello non di tipo

prima prova, con il modello di specializzazione:

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; } 

Clang 3.1 dice:

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. 

secondo tentativo, con un modello di funzione:

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(); } 

Clang dice:

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 dice cose simili.

Si tratta di una limitazione fondamentale?

Domanda bonus: se lo è, allora c'è un modo per gestire tutte le infinite possibilità in una quantità limitata di codice, anche se è un codice meno semplice e generico? (Diventa difficile con puntatori ad esempio: per la stessa ragione per cui non riesco a scrivere template<T> Non credo che si potrebbe scrivere template<T*> neanche.)

prega di non chiedere il motivo per cui sto chiedendo.

+1

Devo dire: non capisco esattamente di cosa hai bisogno –

+2

Credo che si potrebbe riassumere come segue: Lasciamo 'template struct A {}'.E 'possibile (e se sì, come) scrivere un template 'arg' tale che' arg > :: template_' è 'template Array',' arg > :: type' è 'int', e' arg > :: value' è '5' (e di tipo' int'), e inoltre lo rende così generico che ogni possibile argomento modello non di tipo può essere gestito in questo modo. – reima

+0

Questo è fondamentalmente. Grazie per averlo messo più chiaramente di quanto potrei! – glaebhoerl

risposta

2

Questa altra domanda sta chiedendo fondamentalmente la stessa cosa, ma per il modello tipo parametri, piuttosto che di modelli non-tipo parametri: template metaprogramming: (trait for?) dissecting a specified template into types T<T2,T3 N,T4, ...>

Per tipo parametri, è davvero facile. Il codice è simile al seguente:

#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 

Ma per non di tipo parametri, non ho capito se è ancora possibile. È possibile iniziare con il codice dall'aspetto simile

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...)); 
     } 
    }; 
}; 

};

ma Clang (almeno) non lo accetta:

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> 
       ^

e anche se hai fatto quel problema andare via in qualche modo, si avrebbe ancora sostituire std::get con una versione hand-coded constexpr, perché la libreria standard std::get non è constexpr per qualsiasi motivo.

+0

Sì, è praticamente lo stesso problema che ho incontrato nel mio primo esempio. Se un parametro del modello è presente solo nell'elenco dei parametri del modello ma non negli argomenti di specializzazione, non può essere dedotto. Presumibilmente lo standard impone questo, perché altrimenti non sembra qualcosa che sarebbe impossibile. – glaebhoerl

Problemi correlati