首页 > 解决方案 > C 风格转换参考

问题描述

考虑以下:

template<class T>
struct call_fn;

template< >
struct call_fn< void( ) >
{
    using sig = void ( );
    void * fn;
    void call() &&
    {
        static_cast< sig * >( fn )( );
    }
    auto && change()
    {
        return (call_fn<void __vectorcall( )>&&)(*this);
    }
};

template< >
struct call_fn< void __vectorcall( ) >
{
    using sig = void __vectorcall( );
    void * fn;
    void call() &&
    {
        static_cast< sig * >( fn )( );
    }
    auto && change()
    {
        return (call_fn<void ( )>&&)(*this);
    }
};

void __vectorcall fast()
{}
void  stdd()
{}

void foo()
{
    void * f = fast;
    void * st = stdd;
    call_fn<decltype(stdd)> { f }.change().call();
    call_fn<decltype(fast)> { st }.change().call();
}

或者更简单地说,如果您对特定示例不感兴趣:

template<class T>
struct s
{
    using t = T;
    char f;
};

void foo()
{
    auto y = (s<int>&&)(s<float>());
}

在这种情况下,除了元编程之外,对象是相同的,这是一个定义明确的 C 风格转换吗?(因为它不能以任何其他方式使用 C++ 强制转换)

标签: c++language-lawyer

解决方案


(因为它不能以任何其他方式使用 C++ 强制转换)

(s<int>&&)(s<float>());

这种转换可以用 C++ 风格的转换来完成。等效的是:

reinterpret_cast<s<int>&&>(s<float>());

这是一个定义明确的演员表吗

重新解释对另一个的转换引用是明确定义的。

在这种情况下,没有很好地定义通过重新解释的引用进行访问。s<int>是与该地址不同的类型,s<float>并且在该地址处没有s<int>对象。


请注意,这是异常允许联合类型双关的情况(标准布局结构的常见初始序列):

union U {
    s<float> sf;
    s<int>   si;
};

U u;
u.sf = {};
return u.si.f; // well defined

标准参考:

[类.mem]

两种标准布局结构 ([class.prop]) 类型的公共初始序列是按声明顺序排列的最长的非静态数据成员和位字段序列,从每个结构中的第一个此类实体开始,这样相应的实体具有布局兼容的类型,或者两个实体都使用 no_unique_address 属性 ([dcl.attr.nouniqueaddr]) 声明,或者两者都不是,或者两个实体都是具有相同宽度的位域,或者都不是位域。

在具有结构类型 T1 的活动成员的标准布局联合中,允许读取结构类型 T2 的另一个联合成员的非静态数据成员 m,前提是 m 是 T1 和 T2 的公共初始序列的一部分;行为就像T1的相应成员被提名一样。


请注意,也允许重新解释第一个成员的地址:

s<float> sf{};
return *reinterpret_cast<char*>(&sf); // well defined

标准参考:

[expr.reinterpret.cast]

对象指针可以显式转换为不同类型的对象指针。当对象指针类型的纯右值 v 转换为对象指针类型“指向 cv T 的指针”时,结果为static_­cast<cv T*>(static_­cast<cv void*>(v))

[expr.static.cast]

“指向 cv1 void 的指针”类型的纯右值可以转换为“指向 cv2 T 的指针”类型的纯右值,其中 T 是对象类型,而 cv2 与 cv1 具有相同的 cv 限定或大于 cv1 的 cv 限定。...如果原始指针值指向对象 a,并且有一个类型为 T(忽略 cv 限定)的对象 b 可以与 a 指针互转换,则结果是指向 b 的指针

[基础.复合]

如果满足以下条件,两个对象 a 和 b 是指针可互转换的:

  • ...

  • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,...

  • ...


推荐阅读