相信很多人都见过这种代码
1 template <class T>
2 class Test
3 {
4 };
5
6 int main()
7 {
8 Test<int> t;
9 }
这是类模板和模板类的最常见的使用了,但是想想看,见过这种写法吗?
1 //
2
3 MyClass<
std::string()> t;
4
5
注意红色的部分,我没有写错,它的确可以编译通过。这时候一串大大的疑问产生了:怎么类的实例也可以做模板参数吗?不是只有类型才能做模板参数么?难道。。。
我一开始看到这个的时候,也想不明白,怎么会呢?难道是幻觉?我决定测试一下,于是我写了下面一段代码:
1 template <class T>
2 struct return_value
3 {
4 typedef T type;
5 };
6
7 int main()
8 {
9 test<std::string()>::type t;
10 }
编译通过了,可以知道t的类型是:std::basic_string<char,std::char_traits<char>,std::allocator<char>> (void)
很长一串,写简单点就是 std::string (void).
这是个什么东西呢?如果是函数指针,怎么说也要有个*呀,可是没有。那这是什么呢?
它是个函数类型,不是函数指针,函数指针是指向函数类型的指针,所以没有*(感谢eXile)。
我给个例子吧,相信大家对boost::function不陌生吧,看下面的代码:
1 std::string Test()
2 {
3 return "Hello World!";
4 }
5
6 boost::function<std::string()> func(Test);
7
8 int main()
9 {
10 std::cout<<func();
11 }
Hello World应该很熟悉了吧,而那个红色的模板参数呢,其实不是调用std::string的构造函数,而是传入std::string (void)(函数类型)。这个类型呢,没啥用,不能实例化,也不能调用(不是函数指针),它只是作为一种类型的签名而已。主要任务是告诉boost::function这个类,它将要接受的函数是一个接受void为参数,返回std::string的一个函数而已,用来做类型推导。
再看个例子吧,
1 std::string Test(std::string str)
2 {
3 return "Hello " + str;
4 };
5
6 boost::function<std::string (std::string)>
7 func(Test);
8
9 int main()
10 {
11 std::cout<<func("World");
12 }
当把签名改成
std::string (std::string)时,就容易理解了。这个看似和函数声明一样的模板参数,主要是为了让boost::function做类型推导。顺便加个括号,看起来像函数。括号里面是参数的类型,括号外面是返回类型。
这才是以函数指针作为模板类型的代码:
1 std::string Test(std::string str)
2 {
3 return "Hello " + str;
4 }
5
6 template <class T>
7 class Type
8 {
9 typedef T type;
10 };
11
12 int main()
13 {
14 // use function pointor as a template argument, it's OK.
15 Type<std::string (*)(std::string)>::type func = Test;
16 // use the signature as a template argument, complier will tell you it's wrong.
17 Type<std::string (std::string)>::type fun = Test;
18
19 }
最后总结一下,这种类型的模板参数只是作为签名而存在,纯粹是为了做类型推导。不能实例化,不是函数指针,名字叫:函数类型。
posted on 2009-05-24 20:21
尹东斐 阅读(2333)
评论(10) 编辑 收藏 引用