6

I want to define a base template class in a way so that it takes variadic template arguments and defines a virtual method for each argument, where the parameter is the argument type.

E.g. Base<int, bool, string> should give me 3 virtual methods: Foo(int), Foo(bool), and Foo(string).

I tried the following:

template <typename Param>
struct BaseSingle
{
    virtual void Foo(Param) {};
};

template <typename... Params>
struct Base : public BaseSingle<Params>...
{
};

Unfortunately, Foo becomes ambiguous. I can't get the using BaseSingle<Params>::Foo... syntax to work. Is there a way?

I know that, alternatively, I can recursively inherit from BaseSingle and pass in the remaining params. Are there perf implications of that?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Oliver Zheng
  • 7,831
  • 8
  • 53
  • 59
  • Recursive inheritance is normal, e.g. `std::tuple` is implemented that way. I don't see why you'd get a performance hit, your functions don't even override each other and don't pass arguments at runtime calling overriden member. –  Mar 09 '12 at 20:40
  • possible duplicate of [using declaration in variadic template](http://stackoverflow.com/questions/7870498/using-declaration-in-variadic-template) – R. Martinho Fernandes Mar 09 '12 at 20:46
  • 2
    *Some* implementations of `std::tuple` use recursive inheritance. But the good ones don't. ;-) – Howard Hinnant Mar 09 '12 at 21:51
  • @Howard http://stackoverflow.com/questions/9641699/why-is-it-not-good-to-use-recursive-inheritance-for-stdtuple-implementations – Johannes Schaub - litb Mar 09 '12 at 22:13

1 Answers1

5

Here is a suggestion that requires exact type matching:

#include <utility>
#include <typeinfo>
#include <string>
#include <iostream>
#include <cstdlib>
#include <memory>

#include <cxxabi.h>

using namespace std;

// GCC demangling -- not required for functionality
string demangle(const char* mangled) {
  int status;
  unique_ptr<char[], void (*)(void*)> result(
    abi::__cxa_demangle(mangled, 0, 0, &status), free);
  return result.get() ? string(result.get()) : "ERROR";
}

template<typename Param>
struct BaseSingle {
  virtual void BaseFoo(Param) {
    cout << "Hello from BaseSingle<"
         << demangle(typeid(Param).name())
         << ">::BaseFoo" << endl;
  };
};

template<typename... Params>
struct Base : public BaseSingle<Params>... {
  template<typename T> void Foo(T&& x) {
    this->BaseSingle<T>::BaseFoo(forward<T>(x));
  }
};

int main() {
  Base<string, int, bool> b;
  b.Foo(1);
  b.Foo(true);
  b.Foo(string("ab"));
}

But IMO your own suggestion using recursive inheritance sounds more elegant.

Philipp
  • 48,066
  • 12
  • 84
  • 109
  • You need a `std::make_unique` facility :) +1 for that tangled mess in `demangle`. Entertaining stuff – sehe Mar 09 '12 at 21:52
  • I tried this, and have `Derived` inherit from `Base`. It seems that `this->BaseSingle::BaseFoo` does not call the overridden Derived `Foo`, but rather calls the base one, which was the whole point of this virtual function business. – Oliver Zheng Mar 09 '12 at 22:38
  • @MTsoul just rewrite it to `BaseSingle* base = this; base->BaseFoo(forward(x));` to get your virtual dispatch back – je4d Mar 09 '12 at 22:52