Raghu DV
Raghu DV

Reputation: 258

Refer to function of different base class according to template parameter

#include <iostream>
using namespace std;

class c1 {
public:
    void f1() { std::cout << "In f1\n"; }
};

class c2 {
public:
    void f2() { std::cout << "In f2\n"; }
};

template<typename T>
class C: public c1, c2 {
public:
    void f() {

    };
};

int main() {
    C<c2> c;
    c.f();

    return 0;
}

is there any way based on T the function f in C can be mapped to function f1 in c1 and f2 in c2? I am not clear how function f that can be used as a wrapper around f1 and f2 when i am pointing to a specific class using T

Note: I cannot modify class c1 and c2. its out of my scope.

Upvotes: 3

Views: 77

Answers (3)

isp-zax
isp-zax

Reputation: 3873

You can specialise template:

#include <iostream>
using namespace std;
class c1{
        public:
                void f1(){std::cout<<"In f1\n";}
};
class c2{
        public:
                void f2(){std::cout<<"In f2\n";}
};

template <typename T>
class C:public c1, c2 {
        public:
                void f()
                {
                };
};

template<> class C<c1>:public c1, c2 {
        public:
                void f()
                {
                  c1::f1();
                };
};

template<> class C<c2>:public c1, c2 {
        public:
                void f()
                {
                  c2::f2();
                };
};

int main()
{
        C<c2> c;
        c.f();
        return 0;
}

Upvotes: 0

Yes, you can write a template like that. In several ways in fact. If you want to keep C as it is, then it's a simple matter of adding a type trait which contains a pointer to a member function

Live Example

template<typename> struct which_member;

template<> struct which_member<c1> {
    static constexpr void (c1::* func)() = &c1::f1; 
};

template<> struct which_member<c2> {
    static constexpr void (c2::* func)() = &c2::f2; 
};

void f() {
    (static_cast<T*>(this)->*which_member<T>::func)();
}

The key is here (static_cast<T*>(this)->*which_member<T>::func)();. We cast this to the appropriate type pointer, then use the trait to retrieve the pointer to a member. And finally we use the access operator ->* on these two operands to obtain a callable expression. Which we then call (the outer ()).

The cast isn't strictly needed, but I think the error message is more descriptive of the problem if you pass something that isn't a base class of C as the type parameter.

Upvotes: 2

songyuanyao
songyuanyao

Reputation: 172894

You can use constexpr if from C++17. e.g.

void f() {
    if constexpr (std::is_same_v<T, c1>)
        f1();
    else
        f2();
}

LIVE

Note that constexpr if is evaluated at compile-time, as @skypjack commented, for this case, it's pretty fine to be evaluated at run-time too. So the following code works fine too:

void f() {
    if (std::is_same_v<T, c1>)
        f1();
    else
        f2();
}

Upvotes: 3

Related Questions