dic*_*oce 16 c++ inheritance templates types
一位同事最近向我展示了他在网上找到的一些代码.它似乎允许编译时间确定类型是否与另一种类型具有"是"关系.我认为这非常棒,但我不得不承认我对这实际上是如何运作一无所知.任何人都可以向我解释这个吗?
template<typename BaseT, typename DerivedT>
inline bool isRelated(const DerivedT&)
{
DerivedT derived();
char test(const BaseT&); // sizeof(test()) == sizeof(char)
char (&test(...))[2]; // sizeof(test()) == sizeof(char[2])
struct conversion
{
enum { exists = (sizeof(test(derived())) == sizeof(char)) };
};
return conversion::exists;
}
Run Code Online (Sandbox Code Playgroud)
定义此函数后,您可以像这样使用它:
#include <iostream>
class base {};
class derived : public base {};
class unrelated {};
int main()
{
base b;
derived d;
unrelated u;
if( isRelated<base>( b ) )
std::cout << "b is related to base" << std::endl;
if( isRelated<base>( d ) )
std::cout << "d is related to base" << std::endl;
if( !isRelated<base>( u ) )
std::cout << "u is not related to base" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
SLa*_*aks 11
它声明了两个名为的重载函数test,一个采用a Base和一个采取任何东西(...),并返回不同的类型.
然后它使用a调用该函数Derived并检查其返回类型的大小以查看调用的重载.(它实际上使用返回的函数的返回值调用函数Derived,以避免使用内存)
因为enums是编译时常量,所以这一切都是在编译时在类型系统中完成的.由于函数最终不会在运行时调用,因此它们没有实体并不重要.
我不是C++专家,但在我看来,重点是让编译器在两个重载之间做出决定test().如果Derived是Base从那时得到的话,将使用第一个返回char,否则将使用第二个 - 返回char[2].然后,sizeof()操作员确定发生了这些中的哪一个并相应地设置了值conversion::exists.
它非常酷但实际上并不起作用,因为用户定义的转换优先于省略号匹配,而const引用可以绑定用户定义转换的临时结果.所以char*p; is_related<bool>(p);会返回true(在VS2010中测试).
如果要真正测试继承关系,可以采用类似的方法,但使用指针而不是引用.
有什么理由你不会使用这样的东西:
template<typename BaseT, typename DerivedT>
struct IsRelated
{
static DerivedT derived();
static char test(const BaseT&); // sizeof(test()) == sizeof(char)
static char (&test(...))[2]; // sizeof(test()) == sizeof(char[2])
enum { exists = (sizeof(test(derived())) == sizeof(char)) };
}
Run Code Online (Sandbox Code Playgroud)
?
例如:
IsRelated<Base, Derived>::exists
Run Code Online (Sandbox Code Playgroud)
这样您就可以在编译时访问信息.