Using Templated Parameter Functions That Call Type Functions

262 views Asked by At

So I was wondering if it is safe to use a private templated function that inside accesses a function of the type that is passed in. Keep in mind that i ensure myself that only these two types can be passed in and the function exists in both structures. The code runs like I would expect but I have concerns about its safty. Is there a better way to achieve the same outcome? Thank you in advance :)

Types:

struct Typestruct1
{
    int size = 4;

    int getSize() {
        return size;
    }
};


struct Typestruct2
{
    int size = 8;

    int getSize() {
        return size;
    }
};

Class:

class MyClass
{
public:
    void printSizes() {
        std::cout << getSize(t1) << std::endl;
        std::cout << getSize(t2) << std::endl;
    }

private:
    template<typename Type>
    int getSize(Type structType) {
        return structType.getSize();
    }

private:
    Typestruct1 t1;
    Typestruct2 t2;
};

Usage:

MyClass myClass;
myClass.printSizes();

As I expected it prints:

4 8

1

There are 1 answers

0
Fillyjonk On

I would highlight three different approaches:

a) If you are about to use either of the two types only (Typestruct1 and Typestruct2) as a function argument and if these two have a similar structure, it would make more sense to use polymorphism instead of creating a template function. You would create an interface, an abstract base class for Typestruct1 and Typestruct2 with a pure virtual function virtual int getSize() = 0, which you will have to override in each derived class. Example:

#include <iostream>

struct TypestructBase {
    virtual int getSize() = 0;
};

struct Typestruct1 : TypestructBase {
    int size = 4;
    int getSize() override {
        return size;
    }
};

struct Typestruct2 : TypestructBase {
    int size = 8;
    int getSize() override {
        return size;
    }
};

class MyClass {
public:
    MyClass() {
        t1 = new Typestruct1();
        t2 = new Typestruct2();
    }
    ~MyClass() {
        delete t1;
        delete t2;
    }
    void printSizes() {
        std::cout << getSize(t1) << std::endl;
        std::cout << getSize(t2) << std::endl;
    }

private:
    int getSize(TypestructBase *structType) {
        return structType->getSize();
    }

    TypestructBase *t1;
    TypestructBase *t2;
};

int main() {
    MyClass myObject;
    myObject.printSizes();

    return 0;
}

b) If Typestruct1 and Typestruct2 don't have a common base and you would like to use the template function with these two types as arguments, you could use the explicit template instantiation to notify the compiler about it:

template int MyClass::getSize(Typestruct1);
template int MyClass::getSize(Typestruct2);

c) Or you might want to use template specialization if you want to provide different function implementations conditional on arg type in your template function:

template<>
int MyClass::getSize(Typestruct1 structType) {
    // Do something with the type Typestruct1
}

template<>
int MyClass::getSize(Typestruct2 structType) {
    // Do something with the type Typestruct2
}