From my wrapper class Pointer<Base>
I'd like to only return pointers to const: Base const *
.
When casting Pointer<Base>
to Derived const *
I get a compile error:
error C2440: 'static_cast': 'Pointer' can not be converted to 'const Derived *'
(translated from german VS2012)
struct Base { };
struct Derived : public Base { };
template <typename T>
class Pointer {
public:
Pointer(T *t = nullptr) : p(t) { }
//operator T*() { return p; }
operator T const *() const { return p; }
template <typename U>
inline U staticCast() const { return static_cast<U>(d); }
private:
T *p;
};
int main(int argc, char *argv[]) {
Derived d;
Pointer<Base> p(&d);
Derived const *pd = static_cast<Derived const *>(p);
}
If I enable the conversion operator T*() { return p; }
it works.
Why doesn't static_cast
use the const conversion operator?
Or more specifically, since
Derived const *pd = static_cast<Derived const *>(static_cast<Base const *>(p));
works:
Why can static_cast
implicitly cast to Base *
, but not to Base const *
, even though the latter is sufficient for the cast target type?
The standard says:
If there is an implicit conversion sequence from expression to new_type, or if overload resolution for a direct initialization of an object or reference of type new_type from expression would find at least one viable function, then static_cast(expression) returns the imaginary variable Temp initialized as if by new_type Temp(expression);, which may involve implicit conversions, a call to the constructor of new_type or a call to a user-defined conversion operator.
[Emphasis by me]
Workaround
Since this seems like a VisualStudio bug, I will use a workaround instead by means of a templated member function staticCast()
(see sample code above), to be used like this:
Derived const *pd = p.staticCast<Derived const *>();
To allow only casts to U const *
, use SFINAE:
template <typename U>
struct is_pointer_to_const
{
static const bool value = std::is_pointer<U>::value
&& std::is_const<typename std::remove_pointer<U>::type >::value;
};
template <typename U>
inline U staticCast(typename std::enable_if<is_pointer_to_const<U>::value >::type* = 0) const
{ return static_cast<U>(d); }
template <typename U>
inline U staticCast(typename std::enable_if<!is_pointer_to_const<U>::value >::type* = 0) const
{ static_assert(false, "Type is not a pointer to const"); return U(); }
The static_cast operator converts a null pointer value to the null pointer value of the destination type. Any expression can be explicitly converted to type void by the static_cast operator.
The static_cast operator converts variable j to type float . This allows the compiler to generate a division with an answer of type float . All static_cast operators resolve at compile time and do not remove any const or volatile modifiers.
As we learnt in the generic types example, static_cast<> will fail if you try to cast an object to another unrelated class, while reinterpret_cast<> will always succeed by "cheating" the compiler to believe that the object is really that unrelated class.
static_cast − This is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. dynamic_cast −This cast is used for handling polymorphism.
There is only one conversion allowed, so you can convert to Base
, but it cannot be converted afterwards to Derived
.
So you have to use two consecutive casts. It's safer anyway because you state that you know that you are converting from a Base
to a Derived
. You should never have an implicit conversion from a base class to a derived class.
You need to process in two steps as you're trying to convert Pointer<Base>*
---(1)---> Base const*
---(2)---> Derived const*
, with:
Pointer<Base>::operator Base const*
e.g.
Base const* pb = static_cast<Base const *>(p);
Derived const *pd = static_cast<Derived const*>(pb);
Live demo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With