Question

C++

I want to know if a pointer that isn’t already a two-const pointer (e.g. T const * const) can be implicitly or explicitly cast, processed through something (e.g. a function), or otherwise converted, to yield a T const * const, without or before being used to initialize a variable that is declared as a T const * const. How can I do this?

I thought that if I started with a T*, then one const_cast (or two, in case the cast can only cast in one const at a time) would suffice, but apparently it doesn’t. Many variables in the code show a different unsuccessful attempt at yielding T const * const through casting or returning from a function. Every cast failed to return a pointer with a trailing const. (I refer to the const to the left of * as the leading const and the one to the right of * as the trailing const.) Because of the unsuccessful casts, I tried unsuccessfully to force the const through direct initialization. This was compiled in VC11. g++ on stack-crooked.com gives a logically equivalent console output, albeit with different names for typeid(/*...*/).name().

#include <iostream>
#include <typeinfo>
using namespace std;

int const * const foo()
{
    return nullptr;
}

int main()
{
    int x = 7;

    auto a1 = &x;
    cout << typeid(a1).name() << endl;

    auto a2 = const_cast<int const *>(&x);
    cout << typeid(a2).name() << endl;

    auto a3 = const_cast<int * const>(&x);
    cout << typeid(a3).name() << endl;

    auto a4 = const_cast<int const * const>(&x);
    cout << typeid(a4).name() << endl;

    auto a5 = const_cast<int const * const>(a4);
    cout << typeid(a5).name() << endl;

    auto a6 = (int const * const) &x;
    cout << typeid(a6).name() << endl;

    auto a7 = static_cast<int const * const>(a4);
    cout << typeid(a7).name() << endl;

    auto a8 = reinterpret_cast<int const * const>(a4);
    cout << typeid(a8).name() << endl;

    auto a9 = foo();
    cout << typeid(a9).name() << endl;

    int const * const a10 = &x;
    cout << typeid(a10).name() << endl;
    cout << ( typeid(a10) == typeid(a4) ) << endl;

    auto a12 = a10;
    cout << typeid(a12).name() << endl;
    cout << ( typeid(a12) == typeid(a4) ) << endl;
}

Expected results vs. actual results, and questions:

Question numbers correspond to the same-numbered a# variables.

  1. Got expected result int *
  2. Got expected result int const *
  3. Expected int* const, but got int*. Did the const_cast ignore its trailing const argument and why? Since the return is the same constness and type as the argument, did the cast run at all?
  4. Expected int const * const, but got int const*. Did the const_cast ignore its trailing const argument and why?
  5. I wanted to see if const_cast<int const * const> will include a trailing const in the result given that the argument a4 already has a leading const. Expected int const * const. Got int const*. Did the const_cast ignore its trailing const argument and why?
  6. Expected int const * const. Got int const*. Why would the explicit cast still exclude the trailing const?
  7. Expected int const * const. Got int const*. Why would the static_cast exclude the trailing const?
  8. Expected int const * const. Got int const*. Why would the reinterpret_cast exclude the trailing const?
  9. Expected int const * const. Got int const*. Why would an initialization to the int const * const return of a function still exclude the trailing const in the result?
  10. Expected int const * const. Got int const* from the console output but not from the debugger. a10 is explicitly declared as int const * const, so why does the typeid().name() exclude the trailing const? operator== yields 1, so why is the typeid() itself (not just the name) for a10 equivalent to that of a4? The VC11 debugger lists a10’s type as int const * const. Why is it different than the one from typeid() and typeid().name()? Which one is correct?
  11. variable name a11 omitted because it looks like the word “all”.
  12. I expected a12 to be int const * const because it is initialized to a10, which was explicitly declared int const * const. operator== yields 1, so typeid() is still int const*. Got int const* from both the console output and the debugger. Why are they different from the expected result?

Are all casts, function returns, and initializations limited to only casting in one const at a time? Is the leading const the only thing they can cast in?

Was it helpful?

Solution

const_cast does work the way you think it does. However, auto doesn't do what you think it does. auto works similarly to function template parameter deduction (in fact, it's defined in terms of the latter). Now consider:

template<typename T>
void f(T x);

f(42);
int const n = 42;
f(n);

Both calls are to f<int>(), not f<const int>(). Top-level const modifiers are ignored by template parameter deduction. For the same reason, in this example

auto a = 42; a = 84;
auto b = n;  b = 84;

variables a and b are of type int, not const int, and can be modified.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top