user406009
user406009

Reputation:

Any way to have a template function in an abstract base class?

I am trying to make a configuration manager class, that can store arbitrary objects by std::string.

My starting idea for my interface (abstract base class) was this (of course this is horribly incomplete)

class ConfigurationManager
{
public:
   static boost::shared_ptr<ConfigurationManager> create();

   template<typename T>
   virtual T getOption(const std::string& name) = 0;
};

But then my compiler pointed out that template's cannot be virtual(and then I realized that I cannot have exported templates anyways).

Internally I am going to be using boost::any's(pretty much a runtime checked void*), but I do not want to expose boost::any in my interface.

What would be the best way to go about this?

Upvotes: 11

Views: 10502

Answers (3)

Matt Phillips
Matt Phillips

Reputation: 9691

I don't know what boost::any does for you, but aside from that your (only, I think) options are either 1) Make ConfigurationManager a template class, or 2) make ConfigurationManager::getOption non-virtual but use a separate non-template virtual function (called within getOption) that manages the functionality you want in your derived classes. There are also variants on 2), such as including a pointer to an object which specifies the intended functionality of (non-virtual) getOption. This object would be an instance of a class which is itself part of an inheritance hierarchy--the Strategy pattern basically. Seems more complicated though. So basically I am suggesting

class ConfigurationManager
{
   public:
      ...
      template<typename T>
      getOption(...);
   private:
      virtual getOptionSpecial(...) = 0; //Called within getOption
};

The top answer to this SO thread is (in part) why I think this is pretty much all you can do.

Upvotes: 1

Jared Hoberock
Jared Hoberock

Reputation: 11406

An alternative approach would be to pass the name of the derived type to ConfigurationManager:

template<typename Derived>
class ConfigurationManager
{
  public:
    static boost::shared_ptr<ConfigurationManager> create();

  template<typename T>
  T getOption(const std::string& name)
  {
    // call Derived::getOption
    return static_cast<Derived*>(this)->getOption(name);
  }
};

The derived type Foo would then be defined like this:

class Foo : public ConfigurationManager<Foo>
{
  template<typename T>
  T getOption(const std::string& name)
  {
    // do something Foo-specific here
  }
};

The end result is something similar to an abstract virtual function. This idiom is referred to as the curiously recurring template pattern.

Upvotes: 5

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726609

Make a protected virtual abstract function returning boost::any, and a non-virtual, non-abstract, public template function to hide it from the users of your interface.

class ConfigurationManager {
protected:
    virtual boost::any getOptionProtected(const std::string& name) = 0;
public:
    static boost::shared_ptr<ConfigurationManager> create();
    template<typename T> T getOption(const std::string& name) {
        return boost::any_cast<T>(getOptionProtected(name));
    }
};

Upvotes: 9

Related Questions