首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

奇怪的模板参数推导有关问题

2012-03-16 
奇怪的模板参数推导问题先贴上源代码再说问题://test.h#ifndefTEST_H#defineTEST_HtemplateclassTclassT

奇怪的模板参数推导问题
先贴上源代码再说问题:
//test.h
#ifndef   TEST_H
#define   TEST_H

template   <class   T>
class   Test   {
public:
Test(const   T   &   v)   :_value(v)   {}
private:
T   _value;
};

template   <class   T>
inline   Test <T>   make_test(const   T   &f)   {
return   Test <T> (f);
}

#endif/*TEST_H*/

//test.cpp
#include   "test.h "

void   func()   {}

int   main()   {

make_test(func);//A处

typedef   void   (*pfunc)();
pfunc   p   =   func;

make_test(p);//B处
return   0;
}

问题:A处无法编译通过,B处可以。A和B唯一的区别是A用的是函数名func,B用的是显示的指针p。

A处的编译错误如下:
test.cpp(7)   :   error   C2784:   'Test <T>   make_test(const   T   &) '   :   could   not   deduce   template   argument   for   'overloaded   function   type '   from   'overloaded   function   type '

我发现当把make_test的参数类型从const   T&改为T就都能通过编译了。但是不太明白其中道理,大家来帮帮看一下,最好能有一个合理的解释,谢谢了。。。

其实make_test跟STL中的make_pair一样,都是为了方便。
奇怪的是SGI   STL   中的   make_pair参数类型用的都是const   T&,这样也会出现上述模板参数推导问题。而gcc和vc8中的make_pair参数类型正是T。

[解决办法]
make_test(func);//A处
和这个地方换成make_test(&func);//这样应该就可以了 func的类型是 void()(),而不是void(*)()
[解决办法]
func是一个函数名...它代表的是一个地址是一个常量,它不可改变.(就像0x12345678)...它的类型应该为void()...

所以当楼主的程序里调用语句:make_test(func);时,而该函数的申明里它的参数是一个引用类型.但传进来的参数func代表的是一个常量,假设此时该常量的值为0x12345678,见过对一个常量取引用的语句么?所以同样要对这个代表函数地址的func进行引用操作.是不能成功的.此刻它的c++伪代码应该像下面这样:

f =&0x12345678;

这样的语句当然是不能通过编译的,所以这里会出错.

但下面的那条语则不同了.


pfunc p = func;

make_test(p);//B处

这里p代表的是一个变量.它是一个指针.准确的说是一个指向函数的指针,是一个指向类型为
void ()的 函数的指针...当在B处调用make_test(p);时同样make_test()函数要对变量p取引用.这很符合c++的语言规则啊.你想想.对一个变量取引用有什么不对的么?...当然是没有的啦...

[解决办法]
A出错的关键在于函数模板参数推导时得到的模板实参为函数类型,即T = void ().
class Test {
private:
T _value;//T=void (),而C++并不能定义函数变量,所以出错
};

解决这个问题可以显示指定模板实参:
make_test <void (*)()> (func);//显示指定为void (*)()函数指针类型

或者像前面有位说的那样,显示取函数地址,也相当于告述了编辑器模板实参类型:
make_test(&func); //OK
[解决办法]
小刀客说的是比较正确的。
函数/函数指针/函数引用 3者很接近,在很多场合是等价的,但在模板里面,情况很混乱,是不等价的,而且经常出2义性错误。
所以,在处理functor的模板里,应该尽量只使用传值,而不要传引用。编译器将自动推导成函数指针,世界就清净了。

热点排行