Home > front end >  Is there an alternative to overloading or template specialization? I am attempting to call a specifi
Is there an alternative to overloading or template specialization? I am attempting to call a specifi

Time:07-30

I have generated a simpler example of what I am trying to accomplish. I would like to be able to call a function, which returns a class containing two template parameters, based on one of the two templated parameters (Variance).

My hierarchy can be simplified to this.

template<typename T>
class AbstractType {};

template<typename T, Variance Type>
class BaseType : public AbstractType<T> {};

template<typename T, Variance Type>
class FinalType : public BaseType<T, Type>{};

Where FinalType in this example isn't strictly necessary, it also inherits from other templated classes in my actual code, which serves no purpose in this example, so it's been removed.

Here's the example code.

enum class Variance {
    Interval,
    Weighted,
};

template<typename T>
class AbstractType
{
protected:
    AbstractType(T* _Instance) :
        Instance(_Instance) {};

    T* Instance;
};

template<typename T, Variance Type>
class BaseType : public AbstractType<T>
{
protected:
    BaseType(T* _Instance) :
        AbstractType<T>(_Instance) {};
};

template<typename T>
class BaseType<T, Variance::Interval> : public AbstractType<T>
{
protected:
    BaseType(T* _Instance) :
        AbstractType<T>(_Instance) {};

    int Interval;
public:
    void SetInterval(int NewInterval) { Interval = NewInterval; }
};

template<typename T>
class BaseType<T, Variance::Weighted> : public AbstractType<T>
{

protected:
    BaseType(T* _Instance) :
        AbstractType<T>(_Instance) {};

    int Weight;
public:
    void SetWeight(int NewWeight) { Weight = NewWeight; }
};

template<typename T, Variance Type>
class FinalType : public BaseType<T, Type>
{
public:
    FinalType(T* _Instance) :
        BaseType<T, Type>(_Instance) 
    {};
};

struct Interface
{

    template<typename T>
    BaseType<T, Variance::Weighted>* CreateBaseInstance(T t, int Weight) {
        FinalType<T, Variance::Weighted>* OutObj = new FinalType<T, Variance::Weighted>(t);
        OutObj.SetWeight(Weight);
        return OutObj;
    }

    template<typename T>
    BaseType <T, Variance::Interval>* CreateBaseInstance(T t, int Interval) {
        FinalType<T, Variance::Weighted>* OutObj = new FinalType<T, Variance::Interval>(t);
        OutObj.SetInterval(20);
        return OutObj;
    }
};


struct Object {};
void test()
{
    Interface Inter;

    Object Obj;
    Inter.CreateBaseInstance<Object, Variance::Weighted>(Obj, 50);  // Too many template arguments
    Inter.CreateBaseInstance<Object, Variance::Interval>(Obj, 10);  // Too many template arguments

    Inter.CreateBaseInstance<Object>(Obj, 50);  // More than one instance of overloaded function
    Inter.CreateBaseInstance<Object>(Obj, 10);  // More than one instance of overloaded function
}

Additionally, Object being used as the first template is just for testing purposes. I will not know the type in this codebase.

I've been able to resolve this problem by creating multiple functions such as..

template<typename T>
BaseType<T, Variance::Interval>* CreateIntervalInstance(T t, int Interval)…

template<typename T>
BaseType<T, Variance::Weighted>* CreateWeightedInstance(T t, int Interval)…

However, as mentioned earlier, FinalType inherits from another set of classes, so while the above works, it becomes crowded and unsustainable with the number of functions needed to do the simple tasks above.

I have experimented with making the Interface have a template parameter, such as..

// Base Class
template<Variance Variant>
class Interface…

// Specialized
template<>
class Interface<Variance::Interval>…
// Functions to create Interval Instances

//Specialized
template<>
class Interface<Variance::Weighted>…
// Functions to create Weighted Instances

But, I once again run into it becoming unsustainable.

The last thing I am currently looking into is Type Traits, but am unsure if or how that could be implemented to make this simpler.

CodePudding user response:

Without following all of it really in detail, don't you just want e.g.

template<typename T, Variance Type>
auto CreateBaseInstance(T t, int value) {
    // Instead of `auto` maybe `std::unique_ptr<BaseType<T, Type>>`
    auto OutObj = std::make_unique<FinalType<T, Type>>(t);
    
    if constexpr(Type == Variance::Weighted) {
        OutObj->SetWeight(value);
    } else if constexpr(Type == Variance::Interval) {
        OutObj->SetInterval(value);
    }
    
    return OutObj;
}

(I replaced new with std::make_unique, because using raw new like this is generally considered bad practice due to the memory management problems it causes.)

  • Related