我有以下模板成员函数:
template <class ParameterT>
typename boost::enable_if_c<boost::is_base_of<BaseOne, ParameterT>::value
|| boost::is_base_of<BaseTwo, ParameterT>::value, void>::type
MyClass::doSomething(const boost::shared_ptr<ParameterT> ¶m);
调用doSomething(sharedPtrTo_derivedFromBaseOne)
,doSomething(sharedPtrTo_derivedFromBaseTwo)
或doSomething(sharedPtrTo_derivedFromBaseOneAndBaseTwo)
所有工作,使用任何其他参数调用它都不起作用,这确实是我想要的。
现在,在执行上述操作时,我还想再接听两个电话:doSomething_baseOne
和doSomething_baseTwo
。显然,它们应该针对到目前为止的所有调用进行编译(因此我的shared_ptr
参数可以是BaseOne
派生的,也可以是BaseTwo
派生的,或两者兼而有之。我想到了这样的事情:
template<class BaseOneDerived>
void doSomething_baseOne(const boost::shared_ptr<BaseOneDerived> ¶m);
{
std::cout << "doing nothing BaseOne";
}
template<class BaseTwoDerived>
void doSomething_baseTwo(const boost::shared_ptr<BaseTwoDerived> ¶m)
{
std::cout << "doing nothing BaseTwo";
}
//doSomething implementation:
{
doSomething_baseOne(param);
doSomething_baseTwo(param);
}
doSomething_baseOne
,doSomething_baseTwo
专精:
template<>
void MyClass::doSomething_baseOne(const boost::shared_ptr<BaseOne> ¶m)
{
std::cout << "doing something with BaseOne";
}
template<>
void MyClass::doSomething_baseTwo(const boost::shared_ptr<BaseTwo> ¶m)
{
std::cout << "doing something with BaseTwo";
}
现在假设我有这个简单的层次结构:
class A : public BaseOne {};
class B : public BaseTwo {};
class C : public BaseOne, public BaseTwo {};
我想,以下来电:
MyClass X;
X.doSomething(boost::shared_ptr(new A());
X.doSomething(boost::shared_ptr(new B());
X.doSomething(boost::shared_ptr(new C());
要接收以下输出:
//for first call
doing something with BaseOne
doing nothing BaseTwo
//for second call
doing nothing BaseOne
doing something with BaseTwo
//for third call
doing something with BaseOne
doing something with BaseTwo
相反,我收到&#34;什么都不做&#34;消息6次(实际上我没有实现非专业版本,所以我真的只是接收链接时未定义的引用,但是你明白了。)
所以基本上编译器选择默认的doSomething_baseOne
和doSomething_baseTwo
作为比专用版本更好的匹配。这是为什么?我怎样才能克服这一点来实现我想要的目标呢?
答案 0 :(得分:3)
这是因为编译器实例化了以下模板:
template<>
void doSomething_baseOne(const boost::shared_ptr<A> ¶m)
{
std::cout << "doing nothing BaseOne";
}
template<>
void doSomething_baseTwo(const boost::shared_ptr<A> ¶m)
{
std::cout << "doing nothing BaseOne";
}
template<>
void doSomething_baseOne(const boost::shared_ptr<B> ¶m)
{
std::cout << "doing nothing BaseOne";
}
template<>
void doSomething_baseTwo(const boost::shared_ptr<B> ¶m)
{
std::cout << "doing nothing BaseOne";
}
template<>
void doSomething_baseOne(const boost::shared_ptr<C> ¶m)
{
std::cout << "doing nothing BaseOne";
}
template<>
void doSomething_baseTwo(const boost::shared_ptr<C> ¶m)
{
std::cout << "doing nothing BaseOne";
}
这是比你提供的更好的模板专业化。
这样做,使用enable_if技巧:
template<class T>
std::enable_if_t<std::is_base_of<T,BaseOne>::value>
doSomething_baseOne(const boost::shared_ptr<T>& param){
std::cout << "doing something baseOne";
}
template<class T>
std::enable_if_t<!std::is_base_of<T,BaseOne>::value>
doSomething_baseOne(const boost::shared_ptr<T>& param){
std::cout << "doing nothing baseOne";
}
template<class T>
std::enable_if_t<std::is_base_of<T,BaseTwo>::value>
doSomething_baseTwo(const boost::shared_ptr<T>& param){
std::cout << "doing something baseTwo";
}
template<class T>
std::enable_if_t<!std::is_base_of<T,BaseTwo>::value>
doSomething_baseTwo(const boost::shared_ptr<T>& param){
std::cout << "doing nothing baseTwo";
}
或者这样,使用标签发送:
template<class T>
doSomething_baseOne(const boost::shared_ptr<T>& param
,std::integral_constant<bool,true>){
std::cout << "doing something baseOne";
}
template<class T>
doSomething_baseOne(const boost::shared_ptr<T>& param
,std::integral_constant<bool,false>){
std::cout << "doing nothing baseOne";
}
template<class T>
doSomething_baseOne(const boost::shared_ptr<T>& param){
doSmething_baseOne(param,
std::integral_constant<
bool,std::is_base_of<T,BaseOne>::value
>{});
}
template<class T>
doSomething_baseTwo(const boost::shared_ptr<T>& param
,std::integral_constant<bool,true>){
std::cout << "doing something baseTwo";
}
template<class T>
doSomething_baseTwo(const boost::shared_ptr<T>& param
,std::integral_constant<bool,false>){
std::cout << "doing nothing baseTwo";
}
template<class T>
doSomething_baseTwo(const boost::shared_ptr<T>& param){
doSmething_baseTwo(param,
std::integral_constant<
bool,std::is_base_of<T,BaseTwo>::value
>{});
}
更好的解决方案是使用概念。甚至更清洁,constexpr if(C ++ 17)。