2012-03-22 70 views
33

功能one()接受一个参数包。功能两个()接受两个。每个包装都被约束成包装在AB的类型中。为什么不能实例化two()如何在可变参数模板中使用多个参数包?

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

试着gcc和铛。

[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

'一个 ... as' - 这是合法的,即使作为一个参数? – Xeo 2012-03-22 22:31:56

+2

编译器如何知道一个包的结束和另一个包的开始? – ildjarn 2012-03-22 22:32:56

+0

@Xeo:这是合法的AFAIK。两个编译器接受它。 – 2012-03-22 22:33:37

回答

11

我找到了一个解决方案。将每个参数包裹在一个Tuple中。使用一个结构来进行部分特化。这里有一个演示,通过将一个元组作为一个列表并且累积另一个元组来将参数转发给函子。那么,这个人通过复制转发。元组用于类型推导,但函数参数中没有使用元组,我认为它是整洁的。

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

元组是一个很好的编译时间列表。

27

这里是另一种方式使用模板模板参数有几个参数包:

#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

此方法是否也可以应用于类模板? – 2014-10-21 23:49:07

+0

@DrewNoakes我不这么认为,因为我使用函数的参数来打包模板参数。 – 2014-10-24 12:33:37

+0

也许会使用'decltype' ... – 2014-10-24 17:21:32

相关问题