2016-08-31 2 views
3

나는 다른 클래스의 기본 클래스 인 을 가지고 있는데, BC이라고 가정 해 봅시다.재정의 함수에 전달 된 인수를 모르는 경우 기본 클래스에서 재정의 된 메서드를 만드시겠습니까?

클래스 B 및 Cvoidhandle_input 방법이 있어야하지만, 인자 수와 유형 B에서C로 변할 수있다.

는 I는 인수로 포인터을 취하는 함수가 - 상기 방법 handle_input 호출 - 다형 말하기, 즉이B 또는 C 어느 수 있었다. B::handle_input에 전달 된 인수가 C::handle_input에 전달 된 것과 다를 수 있기 때문에 A::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; 
}; 

했다 그러나 결과는 더 많거나 적은 동일, 예상대로입니다.


나는 내 질문에 것 같아요 "당신은 잠재적으로 다수의 최우선 기능에 전달 된 인수를 모를 때 어떻게 기본 클래스에서 오버라이드 (override) 방법을 만들 수 있습니까?"

노트 (내가 틀렸다면 정정 해줘)는 가상이어야한다, 그래서

  • handle_input은 동적 다형성이다.
  • handle_input의 인수 번호를 알 수 없으므로 매개 변수 팩을 사용해야합니다. 여기에 대한 설명과 함께 훨씬 뛰어난 구현을 제공 한
+0

가) 당신은 가상 템플릿 기능을 가질 수 없습니다. B) 가상 함수의 서명에있는 유형은 동일하거나 공변수 여야하며 동일한 개수의 가상 함수가 있어야합니다. – NathanOliver

+0

입력 기본 클래스를 만들고 B에 입력을 그룹화하고 C에 입력을 기본 입력 클래스에서 파생되는 두 개의 다른 클래스로 그룹화한다고 가정합니다. 그런 식으로 클래스 A의 가상 함수는 기본 입력 형식에 대한 포인터를 사용한다는 것을 선언 할 수 있습니다. 그런 다음 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

정말 솔루션의 개념을 좋아합니다. 적당한 보일러 판이있는 것처럼 보입니다. 인자가없는 lamda를 값에 매입하여 똑같은 일을 할 수있는 방법이 있습니까? – RyanP

+0

@ RyanP 당신이 쓴 것을 보여줄 수 있습니까? – user2296177

+0

'return [=] {return f (args ...)]가 아닙니다. };'return f (args ...);와 동일하다. 나는 거기에서 무엇을 놓치고 있습니까? – Garmekain

관련 문제