namespace TestTemp
{
class CBase
{
public:
template
R UICall(const char *name, const P1 &p1, const P2 &p2)
{
return CallMid
}
template
R CallMid()
{
R ret;
CallMe(ret);
return ret;
}
template <>
void CallMid
{
CallMe();
}
void CallMe(std::string &ret)
{
// do something
ret = "hello";
}
......
void CallMe()
{
// do something
printf("void EndCall!\n");
}
};
}
using namespace TestTemp;
int main()
{
CBase oBase;
oBase.UICall
string strT = oBase.UICall
printf("size=%llu, str=%s\n", strT.size(), strT.c_str());
return 0;
}
template <>很显然,这里绕不过去,必须对void型显式特化(否则main函数编译时会报错: 不能定义void型变量)。对大部分项目来说,修改这个问题很容易:只要把特化的代码写在类定义的外面(但要写在namespace下)就搞定了,如第一段代码应该写成这样:
void CallMid()
{
CallMe();
}
namespace TestTemp
{
class CBase
{
public:
template
R UICall(const char *name, const P1 &p1, const P2 &p2)
{
return CallMid
}
template
R CallMid()
{
R ret;
CallMe(ret);
return ret;
}
void CallMe(std::string &ret)
{
// do something
ret = "hello";
}
......
void CallMe()
{
// do something
printf("void EndCall!\n");
}
};
template <>
void CBase::CallMid
{
CallMe();
}
}
using namespace TestTemp;
int main()
{
CBase oBase;
oBase.UICall
string strT = oBase.UICall
printf("size=%llu, str=%s\n", strT.size(), strT.c_str());
return 0;
}
上面的代码在VC和linux上都能顺利编过并运行。但是在我的项目中悲剧了:上面的代码是库代码,而且这是个头文件,真正的工程项目很多文件会include这个头文件,这样在工程项目链接时报错:CBase::CallMid
好吧,你想到了偏特化,我增加一个无用的模板参数Dummy,然后将第一个模板参数R偏特化为void
template
template但是这种解法会造成未使用的复杂对象的构造和析构,产生额外的开销。所以最终使用下面的方法,完美的解决了问题:
R CallMid(D/*Dummy*/)
{
R ret;
CallMe(ret);
return ret;
}
template
void CallMid(void)
{
CallMe();
}
namespace TestTemp
{
template
struct identity { typedef T type; };
class CBase
{
public:
template
R UICall(const char *name, const P1 &p1, const P2 &p2)
{
return CallMid
}
template
R CallMid()
{
return TCallType(identity
}
template
R TCallType(identity
{
R ret;
CallMe(ret);
return ret;
}
void TCallType(identity
{
CallMe();
}
void CallMe(std::string &ret)
{
// do something
ret = "hello";
}
......
void CallMe()
{
// do something
printf("void EndCall!\n");
}
};
}
using namespace TestTemp;
int main()
{
CBase oBase;
oBase.UICall
string strT = oBase.UICall
printf("size=%llu, str=%s\n", strT.size(), strT.c_str());
return 0;
}