2

The following code fails to compile in both MSVC2015 and clang when the comment marks are removed but it compiles as it is.

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;
}

This question is different from a previously asked one because there is not overall const qualifier being casted away.

According to the standard [expr.reinterpret.cast]/7

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)).

In this case, the target “pointer to cv T” is const int * * * which makes T = const int * * and no cv qualifiers. Thus, the result should be static_cast<T*>(static_cast<void*>(v)).

There are constrains about the alignment of T, but those are not relevant here as demonstrated in the static assert. Since the result of reinterpret_cast< const int * * * >( a ) can actually be computed using the intermediate steps, the commented code should compile if uncommented.

Where is the error in my reasoning (if any)?

Community
  • 1
  • 1
Hector
  • 2,464
  • 3
  • 19
  • 34
  • 2
    This is forbidden as per [expr.const.cast]p8, via [expr.reinterpret.cast]p2. – dyp Aug 07 '15 at 16:29
  • @dyp: I read [expr.const.cast]p8 "Converting a function pointer to an object pointer type or vice versa is conditionally-supported.", but I think it should not apply here because there are no function pointers involved. – Hector Aug 07 '15 at 16:34
  • You're quoting [expr.reinterpret.cast]p8. I was referring to [expr.const.cast]p8 and [expr.reinterpret.cast]p2. – dyp Aug 07 '15 at 16:36
  • Yes, I misread your comment ;-) – Hector Aug 07 '15 at 16:40

1 Answers1

2

N3690 5.2.11/8:

The following rules define the process known as casting away constness. In these rules Tn and Xn represent types. For two pointer types:

X1 is T1 cv1,1 * ... cv1,N * where T1 is not a pointer type

X2 is T2 cv2,1 * ... cv2,M * where T2 is not a pointer type

K is min(N,M)

casting from X1 to X2 casts away constness if, for a non-pointer type T there does not exist an implicit conversion (Clause 4) from:

T cv1,(N-K+1) * cv1,(N-K+2) * ... cv1,N *

to

T cv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *

In your example, X1 is const int**, so N is 2, T1 is int, cv1,1 is const, and cv1,2 is empty. X2 is const int***, so M is 3, T2 is int, cv2,1 is const, and cv2,2 and cv2,3 are empty. K is 2. Does there exist an implicit conversion from

T cv1,1 * cv1,2 * = T const**

to

T cv2,2 * cv2,3 * = T**?

No; therefore your cast casts away constness.

And of course we have 5.2.10/2:

The reinterpret_cast operator shall not cast away constness (5.2.11).

Community
  • 1
  • 1
aschepler
  • 70,891
  • 9
  • 107
  • 161