C 风格转换参考

C-style casting references

考虑以下因素:

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++ 转换无法通过任何其他方式完成)

(since it cannot be done any other way using c++ casting)

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

此转换可以使用 C++ 样式转换完成。等价于:

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

is this a well defined cast

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

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


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

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

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

标准参考:

[class.mem]

The common initial sequence of two standard-layout struct ([class.prop]) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types, either both entities are declared with the no_­unique_­address attribute ([dcl.attr.nouniqueaddr]) or neither is, and either both entities are bit-fields with the same width or neither is a bit-field.

In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.


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

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

标准参考:

[expr.reinterpret.cast]

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_­cast<cv T*>(static_­cast<cv void*>(v)).

[expr.static.cast]

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. ... if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b.

[basic.compound]

Two objects a and b are pointer-interconvertible if:

  • ...

  • one is a standard-layout class object and the other is the first non-static data member of that object, ...

  • ...