Search code examples
c++templatescasting

Safely converting between 2 templates classes with common base


Consider the following

template<typename T>
struct Wrapper{ T t; };

template<typename T>
struct Variant1 : public Wrapper< T >
{
    // ... Member types, static members, non virtual functions ... //
}

template<typename T>
struct Variant2 : public Wrapper< T >
{
    // ... Member types, static members, non virtual functions ... //
}

Is there a way to convert for example Variant1<int> & to Variant2<int> & without triggering UB. I've searched SO for answers but most questions related to this are of the form "Is it safe to do it this specific way". My question is there any safe way to do this.

Some ways I found are:

  • direct cast: ( Variant2< int > & ) value or the same using reinterpret_cast
  • cast to Wrapper<int> & and then into Variant2<int> &

Edit

Specific Example:

Variant1< int > val{ .t = 5 };
Variant2< int > & ref = ?Convert?( val );

Goal:

The goal would be to be able to create "Tagged" types which simply act as a proxy around the wrapped type and would prevent accidental mixing of two different tags. However sometimes it is necessary to explicitly convert from one tag to another. This should be a compile time thing, and thus not really cause any overhead.


Solution

  • Is there a way to convert for example Variant1<int> & to Variant2<int> & without triggering UB

    No. It also defeats the whole point of your polymorphism if you're just reinterpreting one derived class as another. What is the point of Wrapper then, and why couldn't you just use std::any?

    The goal would be to be able to create "Tagged" types which simply act as a proxy around the wrapped type and would prevent accidental mixing of two different tags.

    This sounds like Wrapper should contain T and also a separate tag type as a member. Alternatively, a std::variant<Variant1<int>, Variant2<int>> might make sense, if every VariantX can be constructed from a Wrapper. In such a case, you could use std::visit to obtain any "tagged type" you want.

    In any case, you haven't provided enough details for a full solution.