Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic type deduction with const_cast is not working

In my work the use of const_cast is under some circumstances unavoidable.

Now I have to const_cast some pretty complicated types and actually I don't want to write all this type clutter in the const_cast<Clutter> expressions, especially if Clutter is very long.

My first idea was to write const_cast<>(myType), but my compiler cannot deduce the non-const type of myType. So I thought about helping my compiler and I deviced the following approach, which compiles.

#include <stdlib.h>
#include <iostream>

int main(int, char**) {
    const int constVar = 6;
    using T = typename std::remove_cv<decltype(constVar)>::type;
    auto& var = const_cast<T&>(constVar);
    var *= 2;
    std::cout << &constVar << " " << &var << "\n"; // Same address!
    std::cout << constVar << " " << var << "\n";
    return EXIT_SUCCESS;
}

Unfortunately, the program gives me the output 6 12 instead of the expected 6 6, which I really didn't understand?

What is wrong with my approach?

like image 511
Aleph0 Avatar asked Jan 28 '23 00:01

Aleph0


2 Answers

From the documentation of const_cast:

const_cast makes it possible to form a reference or pointer to non-const type that is actually referring to a const object or a reference or pointer to non-volatile type that is actually referring to a volatile object. Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.

So what you have is undefined behavior.

Also of interest is this note from cv type qualifiers.

const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.

like image 182
P.W Avatar answered Feb 05 '23 08:02

P.W


If you have

void foo(const int& a)
{
    const_cast<int&>(a) = 4;
}

then

int a = 1;
foo(a);

is perfectly legal, but

const int a = 1;
foo(a);

invokes an undefined behaviour, because in foo, a was originally const.

This is useful in some case (usually when interfacing old C library), but in most cases, you are doing something wrong and should rethink your solution.

And to answer why const_cast<> isn't a thing, I'd say for two reasons. First, when you do const_cast you should really know what you are doing, if some kind of template deduction was allowed, it would make doing unintended mistakes more likely to occur. And secondly const_cast can also be used to remove volatile and how can compiler know what you want to cast away?

like image 43
Zereges Avatar answered Feb 05 '23 08:02

Zereges