实现一个模板函数,该函数将两个类作为模板参数,如果继承则返回true

时间:2016-09-13 09:52:49

标签: c++ templates c++11

下面是我遇到的代码,它实际上完成了std::is_base_of在C ++ 11或boost::is_base_of中的功能。

辅助函数下面的函数相同:

template<typename D, typename B>
class IsDerivedFromHelper
{
   class No { };
   class Yes { No no[3]; };

   static Yes Test( B* );
   static No Test( ... );
public:
    enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };

};


template <class C, class P> 
bool IsDerivedFrom() {
 return IsDerivedFromHelper<C, P>::Is;
}

有人可以解释枚举Is的内容吗?

什么是静态Yes Test和静态No Test?它们是函数调用吗?

1 个答案:

答案 0 :(得分:10)

class No { }; - 定义一个类,它将具有未定义的大小,不会为零(由标准规定)

class Yes { No no[3]; }; - 定义另一个类Yes,它至少是No的3倍。所以他们保证不同的尺寸。

static Yes Test( B* ); - 声明一个返回Yes的函数,但不给它一个定义(我们不需要一个)。它将匹配任何指向从B派生的对象的指针参数。

static No Test( ... ); - 声明一个返回No的函数(更小,还记得吗?)。如果不能满足更具体的一个(上面),则选择过载。它接受任何参数(但如果参数派生自B,则优先选择重载的其他版本)。

sizeof(Test(static_cast<D*>(0)))在将指针传递给Test时推断出D返回的对象的大小。如果D来自B,那么它将是Yes,否则它将是No

因为“调用”是在非推导的上下文中进行的,所以不会对其进行评估(调用),只选择它并返回返回类型。

其余的可能是不言自明的。结果证明不是:)

所以这一切都放在这里:

enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };

简而言之,这就是说:

“声明一个名为Is的常量,如果使用true调用Test的结果与{{1}的大小相同,则为D*如果调用的结果碰巧是一个不同大小的类型,那么它将是Yes。由于上面的两个重载,当D是B或从它派生的任何东西时,{ {1}}将选择false版本,该版本将返回Test(D*),这显然与Yes的大小相同。如果未选择此重载,则更宽松(但较低的优先级)一个将是。那个返回Yes,显然与Yes(根据定义)的大小不同。“

为什么No'优先级低于Yes(就重载决策而言)?因为它只是。标准将其定义为。

最后:

Test(...)

这将创建一个函数,该函数将为任何两个类类型Test(B*)template <class C, class P> bool IsDerivedFrom() { return IsDerivedFromHelper<C, P>::Is; } 返回上述测试的结果。如果C来自P,则返回true,否则返回false。