以下代码无法在删除注释标记时在MSVC2015和clang中编译,但它会按原样编译。
int main()
{
static_assert( alignof( int * ) == alignof( int * * ), "nope" );
const int * * a = nullptr;
//const int * * * b = reinterpret_cast< const int * * * >( a );
auto c = static_cast< const int * * * >( static_cast< void * >( a ) );
return 0;
}
此问题与previously asked one不同,因为没有整体const
限定符被投放。
根据标准[expr.reinterpret.cast] / 7
可以将对象指针显式转换为不同类型的对象指针。当对象指针类型的prvalue
v
转换为对象指针类型“指向cv T
的指针”时,结果为static_cast<cv T*>(static_cast<cv void*>(v))
。
在这种情况下,目标“指向cv T
的指针”为const int * * *
,这使T = const int * *
和cv
限定符成为可能。因此,结果应为static_cast<T*>(static_cast<void*>(v))
。
T
的对齐存在约束,但这些与静态断言中所示的不相关。由于reinterpret_cast< const int * * * >( a )
的结果实际上可以使用中间步骤计算,因此注释后的代码应该在未注释的情况下进行编译。
我的推理错误在哪里(如果有的话)?
答案 0 :(得分:2)
N3690 5.2.11 / 8:
以下规则定义了称为 cast away constness 的过程。在这些规则中,
Tn
和Xn
代表类型。对于两种指针类型:
X1
是T1
cv 1,1*
... cv 1, N*
其中T1
不是指针类型
X2
是T2
cv 2,1*
... cv 2, M*
其中T2
不是指针类型K 是min( N , M )
从
X1
转换为X2
会抛弃constness,如果对于非指针类型T
,则不存在隐式转换(第4条):
T
cv 1,( N - K +1) {{1} } cv 1,( N - K +2)*
... cv 1, N*
到
*
cv 2,( M - K +1) {{1} } cv 2,( M - K +2)T
... cv 2, M*
在您的示例中,*
为*
,因此 N 为2,X1
为const int**
, cv 1,1 为T1
, cv 1,2 为空。 int
为const
,因此 M 为3,X2
为const int***
, cv 2,1 是T2
, cv 2,2 和 cv 2,3 是空。 K 是2.是否存在来自
int
cv 1,1 const
cv 1,2 { {1}} = T
到
*
cv 2,2 *
cv 2,3 { {1}} = T const**
?
没有;所以你的演员会抛弃常数。
当然我们有5.2.10 / 2:
T
运算符不得抛弃constness(5.2.11)。