Определите несколько методов с параметрами из вариативных шаблонов

Я хочу определить базовый класс шаблона таким образом, чтобы он принимал переменные аргументы шаблона и определял виртуальный метод для каждого аргумента, где параметр — это тип аргумента.

Например. Base<int, bool, string> должен дать мне 3 виртуальных метода: Foo(int), Foo(bool) и Foo(string).

Я пробовал следующее:

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

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

К сожалению, Foo становится двусмысленным. Я не могу заставить работать синтаксис using BaseSingle<Params>::Foo.... Есть ли способ?

Я знаю, что в качестве альтернативы я могу рекурсивно наследоваться от BaseSingle и передать остальные параметры. Есть ли в этом последствия для производительности?


person Oliver Zheng    schedule 09.03.2012    source источник
comment
Рекурсивное наследование нормально, например. std::tuple реализовано таким образом. Я не понимаю, почему вы получите удар по производительности, ваши функции даже не переопределяют друг друга и не передают аргументы во время выполнения, вызывая переопределенный член.   -  person doublep    schedule 10.03.2012
comment
возможный дубликат с использованием объявления в шаблоне с переменным числом аргументов   -  person R. Martinho Fernandes    schedule 10.03.2012
comment
Некоторые реализации std::tuple используют рекурсивное наследование. А хороших нет. ;-)   -  person Howard Hinnant    schedule 10.03.2012
comment
@Howard stackoverflow.com/questions/9641699/   -  person Johannes Schaub - litb    schedule 10.03.2012


Ответы (1)


Вот предложение, которое требует точного сопоставления типов:

#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"));
}

Но IMO ваше собственное предложение с использованием рекурсивного наследования звучит более элегантно.

person Philipp    schedule 09.03.2012
comment
Вам нужно средство std::make_unique :) +1 за этот запутанный беспорядок в demangle. Развлекательные материалы - person sehe; 10.03.2012
comment
Я попробовал это, и Derived унаследовал от Base. Кажется, что this->BaseSingle<T>::BaseFoo не вызывает переопределенную производную Foo, а вызывает базовую, в которой и был весь смысл этой виртуальной функции. - person Oliver Zheng; 10.03.2012
comment
@MTsoul просто перепишите его на BaseSingle<T>* base = this; base->BaseFoo(forward<T>(x));, чтобы вернуть виртуальную отправку. - person je4d; 10.03.2012