相信很多人都見過這種代碼
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
尹東斐 閱讀(2350)
評論(10) 編輯 收藏 引用