2012-03-22 11 views
33

Funzione uno() accetta un pacchetto di parametri. Funzione due() accetta due. Ogni pacchetto è vincolato per essere impacchettato nei tipi A e B. Perché è impossibile istanziare due()?Come posso avere più pacchetti di parametri in un modello variadic?

template <typename T> 
struct A {}; 

template <typename T> 
struct B {}; 

template <typename... Ts> 
void one(A<Ts> ...as) { 
} 

template <typename... Ts, typename... Us> 
void two(A<Ts> ...as, B<Us> ...bs) { 
} 

int main() { 
    auto a = A<int>(); 
    auto b = B<int>(); 

    // Just fine 
    one(); 
    one(a); 
    one(a, a); 

    // All errors  
    two(); 
    two(a); 
    two(a, b); 
} 

Provato con gcc e clang.

[email protected]:~/x/cpp$ gcc -std=c++0x variadic_templates.cpp 
variadic_templates.cpp: In function ‘int main()’: 
variadic_templates.cpp:23:7: error: no matching function for call to ‘two()’ 
variadic_templates.cpp:23:7: note: candidate is: 
variadic_templates.cpp:11:6: note: template<class ... Ts, class ... Us> void two(A<Ts>..., B<Us>...) 
variadic_templates.cpp:24:8: error: no matching function for call to ‘two(A<int>&)’ 
variadic_templates.cpp:24:8: note: candidate is: 
variadic_templates.cpp:11:6: note: template<class ... Ts, class ... Us> void two(A<Ts>..., B<Us>...) 
variadic_templates.cpp:25:11: error: no matching function for call to ‘two(A<int>&, B<int>&)’ 
variadic_templates.cpp:25:11: note: candidate is: 
variadic_templates.cpp:11:6: note: template<class ... Ts, class ... Us> void two(A<Ts>..., B<Us>...) 
[email protected]:~/x/cpp$ clang -std=c++0x variadic_templates.cpp 
variadic_templates.cpp:23:3: error: no matching function for call to 'two' 
    two(); 
    ^~~ 
variadic_templates.cpp:11:6: note: candidate function template not viable: requires at least 1 argument, but 0 were provided                             
void two(A<Ts> ...as, B<Us> ...bs) {} 
    ^
variadic_templates.cpp:24:3: error: no matching function for call to 'two'                                         
    two(a); 
    ^~~ 
variadic_templates.cpp:11:6: note: candidate function not viable: requires 0 arguments, but 1 was provided                                 
void two(A<Ts> ...as, B<Us> ...bs) {} 
    ^
variadic_templates.cpp:25:3: error: no matching function for call to 'two'                                         
    two(a, b); 
    ^~~ 
variadic_templates.cpp:11:6: note: candidate function not viable: requires 0 arguments, but 2 were provided                                 
void two(A<Ts> ...as, B<Us> ...bs) {} 
    ^
3 errors generated. 
+0

'A ... as' - è presente anche legale come parametro? – Xeo

+2

Come fa il compilatore a sapere quando finisce un pacchetto e inizia l'altro? – ildjarn

+0

@Xeo: È legale AFAIK. Due compilatori lo accettano. –

risposta

11

Ho trovato una soluzione. Avvolgi ciascun pacchetto di parametri in una tupla. Utilizzare una struttura per la specializzazione parziale. Ecco una demo che inoltra gli argomenti a un functor consumando una tupla come lista e accumulando un'altra. Bene, questo in avanti copiando. Le tuple sono usate nella deduzione del tipo, ma non si usano tuple nei parametri di funzione, che ritengo sia accurato.

#include <iostream> 
#include <tuple> 

template < typename ... > 
struct two_impl {}; 

// Base case 
template < typename F, 
      typename ...Bs > 
struct two_impl < F, std::tuple <>, std::tuple<Bs...> > { 
    void operator()(F f, Bs... bs) { 
    f(bs...); 
    } 
}; 

// Recursive case 
template < typename F, 
      typename A, 
      typename ...As, 
      typename ...Bs > 
struct two_impl < F, std::tuple< A, As... >, std::tuple< Bs...> > { 
    void operator()(F f, A a, As... as, Bs... bs) { 
    auto impl = two_impl < F, std::tuple <As...>, std::tuple < Bs..., A> >(); 
    impl(f, as..., bs..., a); 
    } 
}; 

template < typename F, typename ...Ts > 
void two(F f, Ts ...ts) { 
    auto impl = two_impl< F, std::tuple <Ts...>, std::tuple <> >(); 
    impl(f, ts...); 
} 

struct Test { 
    void operator()(int i, float f, double d) { 
    std::cout << i << std::endl << f << std::endl << d << std::endl; 
    } 
}; 

int main() { 
    two(Test(), 1, 1.5f, 2.1); 
} 

Le tuple sono una lista di tempo di compilazione molto buona.

27

Ecco un altro modo per avere diversi parametri pack utilizzando parametri di modello modello:

#include <iostream> 

template <typename... Types> 
struct foo {}; 

template < typename... Types1, template <typename...> class T 
     , typename... Types2, template <typename...> class V 
     , typename U > 
void 
bar(const T<Types1...>&, const V<Types2...>&, const U& u) 
{ 
    std::cout << sizeof...(Types1) << std::endl; 
    std::cout << sizeof...(Types2) << std::endl; 
    std::cout << u << std::endl; 
} 

int 
main() 
{ 
    foo<char, int, float> f1; 
    foo<char, int> f2; 
    bar(f1, f2, 9); 
    return 0; 
} 
+0

Questo approccio può essere applicato anche ai modelli di classe? –

+0

@DrewNoakes Io non la penso così, perché uso i parametri delle funzioni per comprimere gli argomenti del template. –

+0

Forse usando 'decltype' in qualche modo ... –

Problemi correlati