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++ 强制转换无法以任何其他方式完成(

(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

标准参考:

[重新诠释]

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

[expr.static.cast]

类型为"指向cv1 void的指针"的prvalue可以转换为"指向cv2 T的指针"类型的prvalue,其中T是对象类型,cv2与cv1具有相同的cv资格,或比cv1更大的cv资格。如果原始指针值指向对象 A,并且存在类型为 T(忽略 CV 限定(的对象 B,该对象可与 A 进行指针互转换,则结果是指向 B 的指针

[基本化合物]

在以下情况下,两个对象 a 和 b 是指针可相互转换的:

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

最新更新