boost::implicit_cast


boost::implicit_cast

在stackoverflow上看到这个帖子, 于是发现了boost::implicit_cast这个小东西.

先来看看这段代码:

struct top {};
struct mid_a : top {};
struct mid_b : top {};
struct bottom : mid_a, mid_b {};

void foo(mid_a&) {}
void foo(mid_b&) {}
void bar(bottom &arg) {
    foo(arg); // 想要调用"void foo(mid_a&)"
}

int main() {
    bottom x;
    bar(x);
    return 0;
}

是无法编译通过的, 因为foo的重载解析有歧义. 那么把bar里的代码改一改, 为了保持C++风格, 我们使用static_cast, 而不是C风格的转换:

foo(static_cast<mid_a&>(arg));

程序编译通过了, 运行起来也没有问题, 然而…

一个月以后我把bar的参数类型修改了一下:

struct top {};
struct mid_a : top {};
struct mid_b : top {};
struct bottom : mid_a, mid_b {};

void foo(mid_a&) {}
void foo(mid_b&) {}
void bar(top &arg) {
    // ... 过了一个月, 这里已经添加了很多代码.
    foo(static_cast<mid_a&>(arg));
}

int main() {
    top x;
    bar(x);
    return 0;
}

代码依旧编译通过, 可是运行时程序挂掉了(假设这几个类里面有许多成员, 并且在foo里对其进行了访问).

发现问题了吗? 原因就在于static_cast太强大了, 强大到可以进行”down-cast”. 于是编译器没有给你任何警告, 就把一个top类型的引用给强制转换成了min_a的引用.

这个时候轮到boost::implicit_cast出场了. 把bar里面的那句foo调用改一改:

foo(boost::implicit_cast<mid_a&>(arg));

于是一个月前的代码依旧可以通过编译, 而一个月后的代码中的错误被编译器揪出来了. 原因在于隐式类型转换不允许”down-cast”, 只能”up-cast”.

这里简要说一下所谓显式和隐式类型转换的区别. 在C++世界的英文里, 我们说”convert”通常指”implicit convert”, 而”cast”指”explicit cast”. 隐式类型转换好理解, 就是你写了个a=b, 而ab不同类型, 编译又不报错, 就说明隐式类型转换发生了, 类似的情况还有在函数调用的参数传递时. 而显式类型转换特指C风格的强制转换((type)obj或者C++中等价的type(obj)), 以及C++风格的四个关键字(static_cast, const_cast, dynamic_cast, reinterpret_cast). 然而这个定义是相当模糊的, 比如一个int类型的x, bool(x)是显式的, 而!!x是隐式的, 其实效果上并没有区别, 只是字面上的不同罢了. (关于cast和convert的区别, 参见这里这里)

所以在bar里我们需要的仅仅是一个隐式类型转换, 然而直接把arg传递给foo的话会出现重载歧义, 于是我们需要告诉编译器到底要进行哪个隐式类型转换. 然而static_cast又太过强大, 它还能做隐式类型转换之外的事情(up-cast), 于是在日后代码演化的过程中留下了bug.

于是boost::implicit_cast应运而生, 它比static_cast弱, 正如它的名字一样, 它只能用来告诉编译器执行什么隐式类型转换.

而它的代码呢? 简单到令人发指:

template <typename T>
inline T implicit_cast (typename mpl::identity<T>::type x) {
    return x;
}

而mpl::identity的定义也极其简单:

template<typename T> struct identity { typedef T type; };

有人要问这个identity干什么用的, 看起来很累赘. 如果没有这个identity, 像”implicit_cast(obj)”这样的代码也能通过编译, 然而它其实什么也没做, obj的类型仍然没变. identity的存在使得函数模板的参数类型推导失效, 因为要推导出T, 首先得知道identity是什么, 而identity又是依赖于T的. 于是就形成了循环依赖, 参数类型推导就失效了. 于是编译器就要求你显式地指定T的类型.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
use global use component_prameter use constant use time_control use LOCAL_RESM implicit none character*20 :: Para_Inlst01,Para_Inlst02,Para_Inlst03 character*20 :: Para_Inlst04,Para_Inlst05,Para_Inlst06,Para_Inlst07 real*8 :: DX_3DV_Input(100),DY_3DV_Input(100),DZ_3DV_Input(100) real*8 :: VELX_3DV_Input,VELY_3DV_Input,VELZ_3DV_Input real*8 :: ANGX_3DV_Input,ANGY_3DV_Input,ANGZ_3DV_Input integer :: CV_Structure_x,CV_Structure_y,CV_Structure_z real*8 :: Gama_CV,Gama_X,Gama_Y,Gama_z integer :: AQCVIN_x,AQCVIN_y,AQCVIN_z real*8 :: AQQ_Input,AQT_Input, AQH_Input character*20 :: INDEX_ISIDE_3DCV, INDEX_OSIDE_3DCV real*8 temp_tterm integer:: N3DV, I3DV integer:: I3DJX, I3DJY, I3DJZ integer:: NX_3DJX,NY_3DJX,NZ_3DJX integer:: NX_3DJY,NY_3DJY,NZ_3DJY integer:: NX_3DJZ,NY_3DJZ,NZ_3DJZ integer:: INCV_X,INCV_Y,INCV_Z integer:: OUTCV_X,OUTCV_Y,OUTCV_Z integer:: Nin_3Dpool,Nout_3Dpool integer:: In_3DPool_X(1000), In_3DPool_Y(1000),In_3DPool_Z(1000) integer:: Out_3DPool_X(1000), Out_3DPool_Y(1000),Out_3DPool_Z(1000) integer:: In_3DV,Out_3DV character*20 :: Connect_InName,Connect_OutName character*20 :: InName_Con(1000),OutName_Con(1000) character*20 :: Index_Oside_3DCV_INPUT(1000), Index_Iside_3DCV_INPUT(1000) integer:: IO_3DPool_X(1000), IO_3DPool_Y(1000), IO_3DPool_Z(1000) character*20 :: Index_IOside_3DCV_INPUT(1000), IOName_Con(1000) integer:: IO_3DV integer:: IO_Cv_X,IO_Cv_Y,IO_Cv_Z ,NIO_3Dpool character*20 :: Index_IOside_3DCV, Connect_IOName integer:: NX_3DV_Input,NY_3DV_Input,NZ_3DV_Input integer:: NTOTAL_3DV,NTOTAL_3DJX,NTOTAL_3DJY,NTOTAL_3DJZ integer:: IZ_3DV ,IX_3DV ,IY_3DV integer:: IZ_3DJX ,IX_3DJX ,IY_3DJX integer:: IZ_3DJY ,IX_3DJY ,IY_3DJY integer:: IZ_3DJZ ,IX_3DJZ ,IY_3DJZ integer:: IX,IY,IZ integer:: IJUNC
最新发布
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值