Home > database >  Casting derived template class from virtual class
Casting derived template class from virtual class

Time:09-16

In my code, I have one abstract class and ~8 child classes. I want to ask, is it possible in C to cast typename and return the calling class? I need something like separate A<int> as A and int. I need something like this:

template <typename T>
class Base
{
    T data;

    virtual void setData(T p_data) = 0;
    virtual ~Base();

    template<class TC<typename TV>>
    operator TC<TV>() const
    {
        TV tmp = (TV) data;
        return TC<TV>(tmp);
    }
};

template <typename T>
class A : public Base<T>
{
    A(T data)
    {
        std::cout << data << std::endl;
    }

    void setData(T p_data) override
    {
        data = p_data;
    }
};

I used to use D. In D, the next code solves this problem (I have included the D code below for a better understanding of what I want):

auto opCast(K, this R)() const
    {
        static if (is(R ClassType : Root!T, alias Root))
            K tmp = cast(K) data;
            return new Root!K(tmp);
        else
            throw new Exception("ClassType isn't equal (T)");
    }

Is there a solution for C ?

CodePudding user response:

If I'm reading your D code correctly, you are basically:

  • taking the ClassType of the this object that is being converted,
  • pattern-matching it to make sure it is a template with 1 argument, and then extracting the type of that template,
  • casting the this object's data member to a specified input type,
  • returning a new object of the template with the specified type as its argument.

There is nothing like ClassType in C , so it is not possible for a base class to obtain the class type of a derived object, unless you use CRTP to pass the derived type as a template parameter to the base class.

However, the operator you have is close to accepting any kind of template type for conversion, your syntax is just a little wrong. Try something more like this:

template <typename T>
class Base
{
public:
    T data;
    ...

    template<template<typename> typename TC, typename TV>
    operator TC<TV>() const
    {
        TV tmp = (TV) data;
        return TC<TV>(tmp);
    }
};

Then something like this would work:

A<int> d(7);
A<float> e = d;
std::cout << e.data << std::endl;

Online Demo

The catch is that this operator will convert to any template that takes an argument that data can be converted to. If you want to restrict the operator to only the same template that is being converted, you will need something more like this:

template <typename T, template<typename> typename Derived>
class Base
{
public:
    T data;
    ...

    template<typename TV>
    operator Derived<TV>() const
    {
        return Derived<TV>(data);
    }
};

template <typename T>
class A : public Base<T, A>
{
    typedef Base<T, A> my_base;

public:
    A(T p_data)
    {
        setData(p_data);
        std::cout << my_base::data << std::endl;
    }

    void setData(T p_data) override
    {
        my_base::data = p_data;
    }
};

Online Demo

  • Related