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]