Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Templates type casting with derivates

I'm trying to cast from one generic to another, say:

myClass<MoreAbstract> anItem = myclass<DerivateFromMoreAbstract> anotherObject;

Or do something like

aFunction(anotherObject); // myclass<DerivateFromMoreAbstract> anotherObject 

where aFunction signature is

aFunction(myClass<MoreAbstract> item);

In fact, myClass is actually a simplified implementation of shared_ptr I found online. I'm wondering if there's any way I can actually switch from one pointer type to another being encapsulated.

Is there any way to do such casting? If so, what would be the correct way to do it?

If it helps anyone, VC++ gives me this error:

Error 1 error C2440: 'type cast' : cannot convert from 'myClass<T>' to 'myClass<T>'
like image 558
tomzx Avatar asked Sep 30 '09 21:09

tomzx


4 Answers

You can't static cast, as they are incompatible types. You can sometimes create an operator to coerce the type instead

#include <iostream>

class A { };

class B : public A { };


template<typename T>
struct holder {
    T* value;

    holder ( T*value ) : value ( value ) { }

    template < typename U > // class T : public U
    operator holder<U> () const
    {
        return holder<U>( value );
    }
};


int main ()
{
    using namespace std;

    B   b;

    holder<B>   hb ( &b );
    holder<A>   ha  = hb;

    cout << boolalpha;

    cout << ( hb.value == ha.value ) << endl;

    return 0;
}

Whether this is a meaningful operation rather depends on the semantic of the template class - if the aFunction can put anything into the handler, you don't want the more specific object being mutated. Hence you copy somehow, either with a coercion operator or with a template copy constructor and assignment. ( the coercion is less code but might result in more objects being created if you don't use reference parameters )

like image 118
Pete Kirkham Avatar answered Nov 18 '22 19:11

Pete Kirkham


Types aren't default convertible in this way (because you might not want objects to do that). In general, you could take two approaches:

Implement a explicit cast function, which might be useful for runtime casts, like boost's shared_ptr dynamic_pointer_cast. You'd end up with something like:

template <typename To, typename From>
myclass<To> myclass_cast(const myclass<From>&)
{ /* do a runtime cast, possibly with exceptions */ }

The second method is a converting constructor, which is good if it is decidable at compile time if they are convertable. For instance, if all classes are convertable from templated on Derived to templated on Base, here's a constructor that will only work when that is true (using enable_if and boost::type_traits):

template <typename To>
class myclass {
  //converting constructor
  template <typename From>
  myclass(const myclass<From>&,
          typename enable_if<boost::type_traits::is_base_of<To, From> >::type* dummy = 0)
  {  }
};
like image 25
Todd Gardner Avatar answered Nov 18 '22 17:11

Todd Gardner


Sorry, that is not possible. (Well, unless you do nasty reinterpret_cast hacks, but you don't want to do that - the end result would not be pretty).

T<Base> and T<Derived> are not related. Compiler cannot assume that - remember that it is entirely possible that T was specialized for Derived to be something completely different.

like image 3
hrnt Avatar answered Nov 18 '22 18:11

hrnt


Templates in c++ aswell as generics in c++.net are not covariant.

Check this question, might give you an idea for a workaround.

like image 1
Yannick Motton Avatar answered Nov 18 '22 18:11

Yannick Motton