Home > other >  Same non-template member function definition for multiple types of template class specilization
Same non-template member function definition for multiple types of template class specilization

Time:01-03

Is it possible that some types of specialized class share one non-template member function definition of a declaration, some types of specialized class share another non-template member function definition with the same declaration in class as above, and the function definitions is in cpp not hpp?

for example: I have a template class A with non-template member function p

template <typename T>
class A {
    void p() {
        print("food.\n");
    }
};

And I have 4 types: banana, apple, fish, steak to specialize the class A for usage in main.cpp: if A is specialized as A<banana>, A<apple>, p print "fruit", if A is specialized as A<fish>, A<steak>, p print "meat".

I would not write 2 times of version: print "fruit" 2 times of version: print "meat" 2 times. Meanwhile, since which type of specialized class print what text has been concrete, is it possible that the 2 versions of p definition could be write in cpp files to reduce cost of compilation?

CodePudding user response:

Maybe use if constexpr to check types and print accordingly.

#include <iostream>

struct Fish {};
struct Steak {};
struct Banana {};
struct Apple {};

template <typename T>
class A {
public:
    void p() {
        if constexpr(std::is_same_v<T, Apple> || std::is_same_v<T, Banana>)
            std::cout << "Fruit\n";
        else if constexpr(std::is_same_v<T, Fish> || std::is_same_v<T, Steak>)
            std::cout << "Meat\n";
    }
};


int main()
{
    A<Fish> fish;
    A<Apple> apple;

    fish.p();
    apple.p();
}

CodePudding user response:

Inheritance might help you out in this case:

class Fruit
{
protected:
    void p() { /* ... */ }
};

class Meat
{
protected:
    void p() { /* ... */ }
};

// general case left unimplemented not to allow arbitrary instantiations
template <typename T>
class A; 
// (alternatively you might provide a default implementation handling the unspecific case)

template <>
class A<Apple> : Fruit
{
public: using Fruit::p;
};

template <>
class A<Fish> : Meat
{
public: using Fruit::p;
};

If it is meaningful to provide a public type hierarchy is up to you to decide, you might then add a generic root class Food with a pure virtual p (then public, of course) while you'd let Fruit and Meat have overrideing p. This would e.g. allow to add the different types of food to a container, but you need to use (smart?) pointers for to avoid object slicing.

Public inheritance with public p in the base classes could be applied for convenience only, too, for not having to specify the using clause – though convenience for the implementer of types usually leads to less clean code in the end...

  • Related