Variadic Templates 的引入,消去了烦冗的模板特化。
一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
 
double do_sum()
{
     return 0;
}
 
template < typename T, typename ... Args >
double do_sum( T&& t, Args&& ... args )
{
     return t + do_sum( args... );
}
 
int main()
{
 
     std::cout << do_sum( 1.0, 2.0, 3.0, 4.0 )
               << std::endl;
 
     return 0;
}

这里需要注意的有两点:

  • double do_sum() 这个函数必须在变长模板函数 double do_sum( T&& t, Args&& … args ) 之前声明
  • 变长模板函数实现中必须使用另外一个函数递归实现

另外要看到,在变长模板函数声明中使用 … 的方法

  • 模板上用的是  template< typename… Args>
  • 函数参数中用的是 double do_sum(Arg … arg)
  • 函数体中用的是 do_sum(arg…)

大致可以看出,有 typename 的时候 .. 跟 typename 后边,否则跟在 Arg 后边,最后则是在参数 arg 后边

 

如果需要知道到底传入了多少个参数可以这样来

 

1
2
3
4
5
template < typename ... Args>
std:: size_t how_many_args(Args ... args)
{
     return sizeof ...(args);
}

 

variadic template 基本使用到这里就差不多了,下边的内容略略而过即可

 

再次注意这个,来个稍微有点复杂的

1
2
3
4
5
6
7
8
template < typename ... T>
void f(T (* ...t)( int , int ));
int add( int , int );
float subtract( int , int );
void g()
{
     f(add, subtract);
}

再来一个多继承

1
2
3
4
5
6
7
template < typename ... Mixins>
class X : public Mixins...
{
   public :
     X( const Mixins&... mixins)
     : Mixins(mixins)... { }
};

 

整数也是可以放在 variadic template 上的

1
2
3
4
template < class ... Types> class Tuple;
// Types is a template type parameter pack
  template < class T, int ... Dims> struct multi array;
// Dims is a non-type template parameter pack

缺省template参数也是可以的,比如

1
2
3
4
5
6
template < class T = char > class String;
String<>* p; // OK: String<char>
String* q; // syntax error
template < typename ... Elements> class Tuple;
Tuple<>* t; // OK: Elements is empty
Tuple* u; // syntax error

 

还有 template template 的这种

 

1
2
3
4
5
6
7
8
9
10
11
template < class T> class A { /* ... */ };
template < class T, class U = T> class B { /* ... */ };
template < class ... Types> class C { /* ... */ };
template < template < class > class P> class X { /* ... */ };
template < template < class ...> class Q> class Y { /* ... */ };
X<A> xa; // okay
X<B> xb; // ill-formed: default arguments for the parameters of a template template argument are ignored
X<C> xc; // ill-formed: a template parameter pack does not match a template parameter
Y<A> ya; // ill-formed: a template parameter pack does not match a template parameter
Y<B> yb; // ill-formed: a template parameter pack does not match a template parameter
Y<C> yc; // okay

 

也特别注意 Y<B> 和 X<B> 无论哪个都不能通过。这是因为在 template 中,模板类型顺序是不可以搞错的,比如:

1
2
3
4
5
6
7
8
9
template < class T1, class T2>
struct A {
void f1();
void f2();
};
template < class T2, class T1>
void A<T2,T1>::f1() { } // OK
template < class T2, class T1>
void A<T1,T2>::f2() { } // erro

于是同样就有

1
2
3
4
5
6
template < class ... Types> struct B {
void f3();
void f4();
};
template < class ... Types>
void B<Types...>::f3() { } // OK

更详细的有

1
2
3
4
5
6
7
8
9
10
11
12
template < class X, class Y> X f(Y);
template < class X, class Y, class ... Z> X g(Y);
 
int i = f< int >(5.6); // Y is deduced to be double
int j = f(5.6); // ill-formed: X cannot be deduced
f< void >(f< int , bool >); // Y for outer f deduced to be
                       // int (*)(bool)
f< void >(f< int >); // ill-formed: f<int> does not denote a
                 // single function template specialization
int k = g< int >(5.6); // Y is deduced to be double, Z is deduced to an empty sequence
f< void >(g< int , bool >); // Y for outer f deduced to be
                        // int (*)(bool), Z is deduced to an empty sequence

 

注意这种特化

1
2
3
4
5
6
7
8
9
10
11
12
template < typename ...>
struct Tuple { };
template < typename ... Types>
void g(Tuple<Types...>); // #1
template < typename T1, typename ... Types>
void g(Tuple<T1, Types...>); // #2
template < typename T1, typename ... Types>
void g(Tuple<T1, Types&...>); // #3
g(Tuple<>()); // calls #1
g(Tuple< int , float >()); // calls #2
g(Tuple< int , float &>()); // calls #3
g(Tuple< int >()); // calls #3

 

还有多个 variadic template 嵌套着用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
template < typename ...>
struct Tuple {};
template < typename T1, typename T2>
struct Pair {};
template < typename ... Args1>
struct zip {
template < typename ... Args2>
struct with {
typedef Tuple<Pair<Args1, Args2>...> type;
};
};
typedef zip< short , int >::with<unsigned short , unsigned>::type T1;
// T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned> >
typedef zip< short >::with<unsigned short , unsigned>::type T2; // error: different number of arguments specified
// for Args1 and Args2
template < typename ... Args>
void g(Args... args)
{
f( const cast< const Args*>(&args)...);
// okay: ‘‘Args’’ and ‘‘args’’ are expanded
f(5 ...); // error: pattern does not contain any parameter packs
f(args); // error: parameter pack ”args” is not expanded
f(h(args...) + args...);
// okay: first ‘‘args’’ expanded within h, second ‘‘args’’ expanded within f.
}

 

再举一个例子:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template < typename T>
void print_comma_separated_list(T&& value)
{
         std::cout<<value<<std::endl;
}
 
template < typename First, typename ... Rest>
void print_comma_separated_list(First&& first,Rest&& ... rest)
{
         std::cout<<first<< "," ;
         print_comma_separated_list(rest...);
}
 
int main()
{
 
     print_comma_separated_list(42, "hello" ,2.3, 'a' );
     print_comma_separated_list( "hello" ,2.3, 'a' );
     print_comma_separated_list(2.3, 'a' );
     print_comma_separated_list( 'a' );
 
     return 0;
}

 

[task]

特别说明:

本文例程多摘自 c++0x N2242,这里可以找到:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf

[/task]