2012-03-23 10 views
1

Ich spiele mit Tupeln als Kompilierzeitlisten. In How can I have multiple parameter packs in a variadic template? habe ich mich mit Code geantwortet, der sowohl in GCC als auch in Clang funktioniert, aber Clang wird jetzt nicht kompilieren, dass ich (was ich denke) perfekte Weiterleitung hinzugefügt habe. Es beschwert sich, dass As... und as... verschiedene Längen in std::forward<As>(as)... haben. Wie kann das sein, wenn As... der Typ as... ist? Es ist As&&... as in den Parametern.Ist das ein Compiler Bug oder ein Programmer Bug?

#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(std::forward<Bs>(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(std::forward<F>(f), std::forward<As>(as)..., std::forward<Bs>(bs)..., std::forward<A>(a)); 
    } 
}; 

template < typename F, typename ...Ts > 
void two(F&& f, Ts&& ...ts) { 
    auto impl = two_impl< F, std::tuple <Ts...>, std::tuple <> >(); 
    impl(std::forward<F>(f), std::forward<Ts>(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); 
} 

Kompilieren mit clang -lstdc++ -std=c++0x multiple_parameter_packs.cpp

clang -lstdc++ -std=c++0x multiple_parameter_packs.cpp 
multiple_parameter_packs.cpp:24:50: error: pack expansion contains parameter packs 'As' and 'as' that have different 
     lengths (1 vs. 2) 
    impl(std::forward<F>(f), std::forward<As>(as)..., std::forward<Bs>(bs)..., std::forward<A>(a)); 
              ~~ ~~^
multiple_parameter_packs.cpp:24:5: note: in instantiation of member function 'two_impl<Test, std::tuple<float &&, 
     double &&>, std::tuple<int &&> >::operator()' requested here 
    impl(std::forward<F>(f), std::forward<As>(as)..., std::forward<Bs>(bs)..., std::forward<A>(a)); 
    ^
multiple_parameter_packs.cpp:31:3: note: in instantiation of member function 'two_impl<Test, std::tuple<int, float, 
     double>, std::tuple<> >::operator()' requested here 
    impl(std::forward<F>(f), std::forward<Ts>(ts)...); 
^
multiple_parameter_packs.cpp:41:3: note: in instantiation of function template specialization 
     'two<Test, int, float, double>' requested here 
    two(Test(), 1, 1.5f, 2.1); 
^
1 error generated. 

Compilation exited abnormally with code 1 at Fri Mar 23 14:25:14 
+2

Reduzierte Testfall: http://ideone.com/YA6ao – kennytm

+0

Der Compiler nicht Ihre Bs –

Antwort

3

Dies scheint ein Fehler in einer alten Version von Clang zu sein. Der Code funktioniert gut mit trunk Clang, entweder mit libstdC++ oder libC++.

$ clang++ multiple_parameter_packs.cpp -std=c++11 -stdlib=libc++ 
$ ./a.out 
1 
1.5 
2.1 
1

Ich glaube nicht, dass dies:

void operator()(F&& f, A&& a, As&&... as, Bs&&... bs) 

durchaus möglich ist.

Ein Parameter-Pack sollte das letzte Argument sein, und As&&... as wird gefolgt von einem anderen Paket hier.

+0

Parameter Packs mag am Ende sein sollte, wenn sie nicht innerhalb eines anderen Typs (wie 'void foo (Tupel sind , Tupel ) '), muss aber nicht sein. Wenn sie nicht vorhanden sind, können sie nicht automatisch abgeleitet werden. Und wenn Sie sie explizit angeben, scheint das erste Paket in der Vorlagenparameterliste alle verbleibenden Vorlagenparameter an diesem Punkt zu erhalten. Spätere Packs sind leer und wenn es Nicht-Pack-Parameter gibt, wird das Template nicht funktionieren, da keine Template-Parameter übrig bleiben: 'template void f(); // f kann nie instanziiert werden – bames53

+0

Funktionsparameter von operator() sind in nicht darstellbarem Kontext. Der Compiler hat z.B. bis As ... während der Ableitung in der Struktur, die operator() enthält. Wie ... die restlichen Params von Bs nicht auffressen ... weil es Arity ist, wird bereits abgeleitet. –