views:

278

answers:

5

I've got a conversion operator that returns a const pointer, and I need to const_cast it. However, that doesn't work, at least under MSVC8. The following code reproduces my problem:

class MyClass {
public:
    operator const int* () {
        return 0;
    }
};

int main() {
    MyClass obj;
    int* myPtr;
    // compiles
    const int* myConstPtr = obj;
    // compiles
    myPtr = const_cast<int*>(myConstPtr);
    // doesn't compile (C2440: 'const_cast' : cannot convert from 'MyClass' to 'int *')
    myPtr = const_cast<int*>(obj);
}

Why is that? It seems counter-intuitive. Thanks!

+1  A: 

You can only use const_cast to convert to a non-const pointer of the same type (to cast away constness). To cast between unrelated types you need reinterpret_cast.

Martin Liversage
Thanks! I just thought the compiler would figure out `MyClass` can be converted to `int*` automatically, as it did in "`const int* myConstPtr = obj`"
Pedro d'Aquino
No, no, no! He created conversion operator from MyClass to int * so the types *are* related. static_cast is apropriate. reinterpret_cast won't invoke the operator. Luckily it won't compile as obj is not a pointer and reinterpret_cast requires either a pointer or an integer type and obj is neither.
Tadeusz Kopec
A: 

Probably it would be clearer to your compiler if you do something like:

myPtr = const_cast<int*>(obj());

I haven't tried yet, thought.

EDIT: Shouldn't the operator declaration be something like:

const int* operator () {
yeyeyerman
Doesn't work: C2064: term does not evaluate to a function taking 0 arguments.
Pedro d'Aquino
I've always used: const int* operator() () { ... } - not sure where the OP's function definition came from, but apparently it compiles.
Samir Talwar
The OP's definition is of a conversion operator to const int*. Samir's definition is of the "function call" operator() taking no parameters and returning const int*. Although the two operators have the same inputs and output, they are used by the compiler in different situations.
Steve Jessop
-1, the question is about conversion operator, not `operator()`.
avakar
Should I leave this answer for people that make the same mistake as me? Or should I just delete it?
yeyeyerman
+1  A: 

Think of const_cast<> as a function template

template <typename Target, typename Source>
Target const_cast( Source src );

(that's not how it's implemented, but it helps here to imagine it was). Then Source is deduced as MyClass, and there's nothing const_cast can do to get an int* from a MyClass.

What you want is either of the following:

const_cast<int*>( static_cast<const int*>(obj) /* invokes operator const int* */ );
// or
const_cast<int*>( obj.operator const int*() );
Yes, `myPtr = const_cast<int*>(obj.operator const int *());` does work! That is one ugly piece of code, though.
Pedro d'Aquino
+4  A: 

To make it work you have to do :

myPtr = const_cast<int*>(static_cast<const int*>(obj));

When you const_cast directly, the compiler look for the cast operator to int*.

neuro
+1  A: 

const_cast can only change the constness of a type. If you want to call the implicit operator you have you need a static_cast and then a const_cast. While it's annoying it makes sure you are explicit in what you are doing.

myPtr = const_cast<int*>(static_cast<const int*>(obj));

You can also use the old school c-style cast operator

myPtr = (int*)(const int*)obj;

But this is highly discouraged for several reasons:

  • It isn't grepable
  • You can very easily do more than you intended. Most of the time you don't want to mess with const_cast type operations and using static_cast enforces this. In fact you very rarely want a const_cast. If you find yourself doing it regularly you have some design mistakes.

Edit: I was slightly off, I fixed it now. It makes the c-style cast a little uglier

Matt Price
The C-style cast is also discouraged in this case for the reason that it doesn't compile - he's trying to cast an instance of MyClass, not a pointer.
Steve Jessop
lol, whoops, I fixed it now.
Matt Price