0

One cannot have a virtual template method in C++. I want to have an interface and some classes which implement it. For example:

class Logger {
   public:
    template<typename... Args>
       virtual void Error(const std::string& message, Args... args) const = 0;
    
};

class ConsoleLogger : public Logger {    
   public:
   template<typename... Args>
         void Error(const std::string& message, Args... args) const{} 
};

Is there any work-around? I still want to use the interface.

1 Answers1

1

As much as "prefer composition over inheritance" tends to be parroted blindly, it does comes in handy here.

class LoggerImpl {
public:
  virtual ~LoggerImpl() {}
  virtual void dispatch(const std::string& message, std::vector<std::string> args) = 0;
};

class Logger {
   std::unique_ptr<LoggerImpl> _impl;
   public:
    Logger(std::unique_ptr<LoggerImpl> impl) : _impl(impl) {}
    
    template<typename... Args>
    void Error(const std::string& message, Args... args) const {
      std::vector<std::string> args_as_strings;
      // Make strings from args

      _impl->dispatch(message, std::move(args_as_strings));
    }
};

How you actually pass the args to the _impl doesn't have to be a vector. That's mostly an implementation detail. As long as whatever mechanism you use is "virtual-friendly". It'll work fine.

  • Thank you! I am not allowed to use a vector though, because it can allocate dynamically. Maybe I should use an array. – Liviu Dorobantu Jun 04 '21 at 15:24
  • @LiviuDorobantu Using an array is a bad idea. `Args... args` is an open-ended list, so it should get packed into an open-ended container. This restriction really changes things, and a CRTP solution is a lot more suitable under those circumstances. –  Jun 04 '21 at 15:26
  • Ok, thank you so much Frank! I have no idea what CRTP is. I will study it. Thanks again! – Liviu Dorobantu Jun 04 '21 at 15:28
  • @LiviuDorobantu A final note: "I am not allowed to use a vector though, because it can allocate dynamically" Just so you know, simply passing a string as one of the arguments could dynamically allocate memory. You probably want the signature to be `Args&&... args` –  Jun 04 '21 at 16:06
  • Yeah, you are right. I should use Args&&. Thanks! – Liviu Dorobantu Jun 04 '21 at 16:27