一个高效的C++类型转换判断实现

2017-09-13  本文已影响0人  ColeWang

最近在网上看到了一个C++类型转换判断的高效实现,分享出来共同学习。作者使用了sizeof关键词、函数重载与可变参数的功能,功能实现得简洁优雅。Talk is cheap, show me the code~

#include <iostream>
using namespace std;
template<class T, class U>
class CHECK_TYPE{
    class OTHER {char st[2];};
    static char Test(U);
    static OTHER Test(...);
    static T USAGE();
public:
    enum {result = sizeof(Test(USAGE())) == sizeof(char)};
};
class A {
};
class B : public A {
};
class C {
};
int main(){
    cout << CHECK_TYPE<double, int>::result << endl;
    cout << CHECK_TYPE<int, double>::result << endl;
    cout << CHECK_TYPE<B, A>::result << endl;
    cout << CHECK_TYPE<C, A>::result << endl;
}

分析:

代码中用到了可变参数。可变参数最典型的应用大概就是printf和scanf,原理是通过函数调用时候将类型、数目可变的参数全部压入函数调用栈,并定义了参数获取的宏来实现。以下面的函数定义为例,

void test(int count, ...)
{
    ... //do some stuff
}

由于函数参数压栈顺序是从右至左,所以在各个可变参数压入调用栈之后,count变量被压入相邻的低位栈地址(由于栈空间的使用由高位地址到低位地址增长)。使用传入的可变变量时,需要依赖count变量来初始化可变参数的初试地址。以上面函数的实现为例:

#include<stdarg.h>
//假设传入的可变参数都是整形变量,并且由count指示传入的可变参数的具体数量
void test(int count, ...)
{
    va_list st;
    va_start(st,count);
    for(int i = 0; i < count; ++i)
    {
        cout<<va_arg(st, int)<<endl;
    }
    va_end(ap);
}

其中使用va_list类型表示可变参数,并用到了三个宏,分别是va_start、va_arg、va_end来实现可变参数的访问。va_list在stdarg.h头文件中被定义为char *类型

typedef char * va_list;

而三个宏的定义如下(这里只找到了win平台的实现,Linux平台的实现应该与之类似):

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_end(ap) ( ap = (va_list)0 )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

通过宏定义,不难看出

最后,回到文章题目,关于类型转换判断的功能,C11中有stl::is_convertable的新feature,但是这个版本的实现显得简洁易懂。

感谢code作者 yunchenglu

上一篇 下一篇

猜你喜欢

热点阅读