booNlatoT
booNlatoT

Reputation: 611

Extending abstract base class with class template

How can I extend an abstract base class using templates for the extensions when I also wish to conditionally compile the overrides for the pure virtual functions?

Example: Given the base class

class AbstractBase {
public:
  virtual void func() = 0;
};

I thought of extending with something like

enum class Opts{FOO, BAR};

template<Opts opt>
class Derived : public AbstractBase {
public:

  template<Opts op = opt>
  typename std::enable_if<op == Opts::FOO, void>::type func() {
    std::cout << "Foo" << "\n";
  }

  template<Opts op = opt>
  typename std::enable_if<op == Opts::BAR, void>::type func() {
    std::cout << "BAR" << "\n";
  }

};

My idea is that when one of the func get to compile in the extended class, then everything's good. However, I can't get it to work.

Derived<Opts::FOO> obj;

Will not compile because the derived class is is still abstract. I'm using templates because I want the compiler to pick only one member function to compile.

Thanks.

Upvotes: 0

Views: 541

Answers (2)

user2249683
user2249683

Reputation:

You may specialize the function instead:

#include <iostream>

class AbstractBase
{
    public:
    // You should have a virtual destructor:
    virtual ~AbstractBase() {}
    virtual void func() = 0;
};

enum class Opts
{
    FOO, BAR
};

template<Opts opt>
class Derived: public AbstractBase
{
    public:
    void func() override;
};

template<>
void Derived<Opts::FOO>::func()
{
    std::cout << "Foo" << "\n";
}

template<>
void Derived<Opts::BAR>::func()
{
    std::cout << "BAR" << "\n";
}

int main()
{
    Derived<Opts::FOO> foo;
    AbstractBase& bfoo = foo;
    bfoo.func();
    Derived<Opts::BAR> bar;
    AbstractBase& bbar = bar;
    bbar.func();
}

However, I consider mixing dynamic polymorphism (virtual) and static polymorphism (templates) a bad design (there might be exemptions).

Upvotes: 1

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145239

Just specialize the class template for each to-be-treated-specially enum value, e.g.,

enum class Opts{foo, bar};

template<Opts opt>
class Derived;

template<>
class Derived<Opts::foo>
    : public AbstractBase
{
public:
    void func() override
    {
        std::cout << "Foo" << "\n";
    }
};

template<>
class Derived<Opts::bar>
    : public AbstractBase
{
public:
    void func() override
    {
        std::cout << "bar" << "\n";
    }
};

Where you want some general common stuff that's not in AbstractBase, you can either inherit it in, or add it in via CRTP in a most derived class.

Disclaimer: off the cuff code, not compiled.

Upvotes: 1

Related Questions