下面是我遇到的代码,它实际上完成了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
?它们是函数调用吗?
答案 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。