2016-12-07 5 views
2

템플릿 펑터를 만들려고합니다.이 펑션 툴은 매개 변수 개수에 관계없이 인자 객체 및 멤버 함수로 사용됩니다. 템플릿으로 코드를 올바르게 작성하는 방법을 알 수 없습니다.모든 매개 변수가있는 템플릿 펑크 터

template<typename ItemT, 
    class T, 
    typename ...Args> 
struct Builder 
{ 
    ItemT operator()(T& object, ItemT (T::*method)(Args...), Args && ... args) 
    { 
     return (object.*method)(std::forward<Args>(args)...); 
    } 
}; 

struct Object 
{ 
    int method(int, int, int) { return 4; } 
}; 


int main() 
{ 
    Object obj;  
    Builder<int, Object>()(obj, &Object::method); // Error here 
} 

매개 변수없이 개체 :: 메서드를 컴파일하면 코드가 컴파일됩니다. 그러나 매개 변수가있는 경우 - 아니요.

설명 프로젝트 파일 라인 억제 상태가 오류 C2664 'INT 빌더 :: 연산자() (T &, ItemT (객체 __thiscall :: *) (무효)가)'

심각도 코드 : INT '에서 인수 2를 변환 할 수 없습니다 (__thiscall Object :: *) (int, int, int) 'to'int (__thiscall Object :: *) (void) '초안 c : \ drafts \ main.cpp 139

+3

당신이'Builder' 객체를 선언했을 때'typename ... Args'가 무엇인지 정의하는 것을 잊어 버렸습니다. – NathanOliver

+0

당신은'Builder '를 필요로합니다. 그리고 실제로'Object :: method'가 원하는 3 개의 int를 인수로 전달해야합니다. 보다 일반적으로, 운동의 요점이 무엇인지는 명확하지 않습니다. 당신은 정말로 어떤 문제를 해결하려고합니까? –

+0

네이선이 말한 바. 표준 라이브러리가 객체를 생성하는 다양한 "make_ *"자유 함수를 제공하는 이유이기도합니다. 따라서 템플릿 인수의 공제가 발생할 수 있습니다. C++ 1z를 사용하면 생성자는 클래스의 템플릿 매개 변수를 추론하여 코드를 유효하게 만들 수 있습니다. – StoryTeller

답변

4

Builder의 현재의 정의, 이것은 당신이 그것을 인스턴스화해야하는 방법은 다음과 같습니다

Builder<int, Object, int, int, int>()(obj, &Object::method, 0, 0, 0); 
// ^ ^ ^^^^^^^^^^^^^       ^^^^^^^ 
//  ItemT | |          | 
//    T Args...        args... 

args... 매개 변수 확장전화는 Builder에 전달 된 TArgs... 팩과 일치해야합니다. 이 경우 유형에

int main() 
{ 
    Object obj;  
    Builder<Object>()(obj, &Object::method, 0, 0, 0); 
} 

:

template<typename T> 
struct Builder 
{ 
    template <typename TFnPtr, typename... Args> 
    auto operator()(T& object, TFnPtr method, Args && ... args) 
    { 
     return (object.*method)(std::forward<Args>(args)...); 
    } 
}; 

은 위의 Builder는 다음과 같이 사용할 수 있습니다

wandbox example


여기에 대안 덜 엄격한 디자인이다 멤버 함수 포인터TFnPtr을 통해 추론되며 특정 매개 변수 집합에 제약되지 않습니다. variadic 매개 변수는 더 이상 Builder의 일부가 아니며 - Builder::operator()의 일부이므로 추론하여 (object.*method)으로 전달할 수 있습니다.

wandbox example

1

당신은 모두 Builder에 템플릿을 피하고 전적으로 템플릿 인수 공제에 의존 할 수 있습니다 : 나는 두 개의 매개 변수를 사용하기로 결정했습니다

struct Builder { 
    template <typename Obj, typename R, typename ... FArgs, typename ... Args> 
    R operator()(Obj& obj, R (Obj::*fn)(FArgs...), Args&&... args) { 
     return (obj.*fn)(std::forward<Args>(args)...); 
    } 
}; 

완벽한 전달을 할 수 있도록 팩 다음 operator() 통화의 가치 범주 반드시 대상 메서드와 일치하지는 않습니다. 또한 멤버 함수 포인터를 적용 할 때 암시 적으로 인수를 변환 할 수 있습니다. 이 구현은 const 메소드가 Obj과 일치하지 않습니다.

물론 auto 반환 유형 (C++ 14) 또는 후행 반환 유형 (C++ 11)을 사용하여 약간 긴장을 풀 수 있습니다. Vittorio의 대답은 이미 C++ 14 방식을 제시 했으므로 필자는 후자에 대해 다룰 것이다.

template <typename Obj, typename FnPtr, typename ... Args> 
auto operator()(Obj& obj, FnPtr fn, Args&&... args) 
    -> decltype((obj.*fn)(std::forward<Args>(args)...)) { 
    return (obj.*fn)(std::forward<Args>(args)...); 
} 

그런 다음, 사용이 간단 할 것이다 : :이 operator()는된다 Coliru에

Object obj; 
Builder()(obj, &Object::method, 0, 0, 0); 

live demo.