2016-08-31 8 views
3

私は抽象クラスに他のクラスの基本であるを持っている、のは、BCをしましょう。オーバーライド関数に渡された引数がわからない場合は、ベースクラスでオーバーライドされたメソッドを作成しますか?

クラスBCvoidタイプhandle_input方法を有していなければならないが、引数の数とタイプは、BからCに変化してもよいです。

Iはまた、引数としてポインタをとる機能を有する - 多形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; 
}; 

しかしテンプレートはコンパイル時に計算されるため、エラーが発生し、仮想ながら、実行時に使用されている:私はクラス何かなどを作成するためのLED

私も

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

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

をしました。しかし、予想通りの成果は、多かれ少なかれ同じです。


私は私の質問はだろうと思い、「あなたが潜在的に複数のオーバーライド関数に渡される引数を知らないとき、どのようにあなたは、基本クラスでオーバーライドされたメソッドを作成することができますか?」

注意事項(私が間違っているなら、私を修正):

  • handle_inputが動的に多型であるので、それを仮想なければなりません。
  • handle_inputの引数番号が不明なため、パラメータパックを使用する必要があります。私はここでの説明で非常に優れた実装を提供してきました
+0

A)あなたは、仮想テンプレート機能を持つことができません。 B)仮想関数のシグネチャ内の型は、同じか共変でなければならず、同じ数でなければならない。 – NathanOliver

+0

入力基本クラスを作成してBに入力をグループ化し、Cへの入力をその基本入力クラスから派生した2つの異なるクラスにグループ化するとします。そうすれば、クラスAの仮想関数は基本入力型へのポインタを取ることを宣言できます。次に、BとCの中で動的キャストを行い、適切な入力クラスを取得する必要があります。これはおそらく、基本入力クラスで宣言されていないゲッター関数が異なるでしょう(2つの入力タイプ)...それはきれいだと言っていないが、それを持っていなければならない場合... – 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

関連する問題