2016-08-31 5 views
3

У меня есть абстрактный класс , который является базовым для других классов, скажем B и C.Создайте метод override в базовом классе, если вы не знаете аргументы, переданные в функции переопределения?

Классы B и C должны иметь handle_input метод void типа, но число аргументов и типы могут варьироваться в зависимости от B до C.

У меня также есть функция, которая принимает указатель к в качестве аргумента - полиморфно говоря, это может быть либо , B или C - и вызывает метод handle_input.


Проблема возникает при определении A::handle_input, так как аргументы, передаваемые B::handle_input могут отличаться от тех, которые прошли в C::handle_input.

, что светодиоды мне создать в классе А что-то вроде:

/* base class */ 
class A { 
    template <class... FUNCTION_ARGS> 
    virtual void handle_input(FUNCTION_ARGS&&...) = 0; 
}; 

Но ошибки происходят, потому шаблон вычисляется во время компиляции, в то время как виртуальный используется во время выполнения.

Я также сделал

class A { 
    template <class... FUNCTION_ARGS> 
    using input_handler = function<void(FUNCTION_ARGS&&...)>; 

    template <class... FUNCTION_ARGS> 
    input_handler<FUNCTION_ARGS...> handle_input; 
}; 

Но результат более или менее такой же, как и ожидалось.


Я предполагаю, что мой вопрос будет «Как вы можете создать переопределен метод в базовом классе, когда вы не знаете, аргументы, передаваемые потенциально нескольких первостепенных функций?»

Notes (поправьте меня, если я ошибаюсь):

  • handle_input динамически полиморфный, поэтому он должен быть виртуальными.
  • Номер аргумента handle_input неизвестен, поэтому необходимо использовать пакеты параметров.
+0

A) вы не можете иметь виртуальные функции шаблона. B) типы в сигнатуре виртуальной функции должны быть одинаковыми или ковариантами, и их должно быть одинаковое число. – NathanOliver

+0

Я предполагаю, что вы можете сделать базовый класс ввода, а затем сгруппировать входы в B и входы в C в 2 разных класса, которые вытекают из этого базового класса ввода. Таким образом, виртуальная функция класса А может объявить, что она принимает указатель на базовый тип ввода. Затем вам нужно будет выполнить динамическое преобразование внутри B и C, чтобы получить соответствующий класс ввода, который, вероятно, будет иметь разные функции getter, которые не объявлены в базовом классе ввода (учитывая, что это не является общим для двух типов ввода) ... не говорю, что это чисто, но если вам нужно это сделать ... – RyanP

ответ

2

Я предоставил значительно превосходящую реализацию с объяснением здесь:

https://codereview.stackexchange.com/q/140510/88422


Чтобы обойти то, что говорит NathanOliver, вы можете использовать замыкание. Они будут хранить свои аргументы, и вы можете называть их полиморфно.

Отказ от ответственности: Это очень баребонная реализация, чтобы показать технику.

template<class F, class... Args> 
auto make_closure(F&& f, Args&&... args) noexcept 
{ 
    return [=] { return f(args...); }; 
} 

struct fn_base 
{ 
    virtual ~fn_base() = default; 
    virtual void invoke() = 0; 
}; 

template<class T, class... Args> 
struct fn : public fn_base 
{ 
    using closure_t = decltype(make_closure(std::declval<T>(), std::declval<Args>()...)); 
    closure_t closure_; 

    fn(closure_t&& closure) : closure_{ std::move(closure) } {} 

    void invoke() override 
    { 
     closure_(); 
    } 
}; 

template<class F, class... Args> 
auto make_fn(F&& f, Args&&... args) 
{ 
    return fn<F, Args...>{ make_closure(std::forward<F>(f), std::forward<Args>(args)...) }; 
} 

Пример использования:

#include <iostream> 

void f(int, char) 
{ 
    std::cout << "f(int, char)\n"; 
} 

void g(double) 
{ 
    std::cout << "g(double)\n"; 
} 

int main(int, char*[]) 
{ 
    auto df0 = make_fn(&f, 1, 'c'); 
    auto df1 = make_fn(&g, 0.5); 
    fn_base* f0 = &df0; 
    fn_base* f1 = &df1; 
    f0->invoke(); 
    f1->invoke(); 
} 
+1

Мне очень нравится концепция решения. Похоже, что есть приличное количество котельной плиты, есть ли способ сделать то же самое, просто передав без аргументов лампу со значениями, встроенными в них? – RyanP

+0

@RyanP Не могли бы вы показать мне (с кодом), что вы хотели бы написать? – user2296177

+0

Не 'return [=] {return f (args ...); }; 'так же, как' return f (args ...); 'в этом контексте? Что мне там не хватает? – Garmekain