4

큰 클래스의 개인 데이터 내부의 멤버 클래스에 대한 함수 포인터 인 매개 변수를 사용하는 템플릿 클래스의 함수를 작성하려고합니다. 해당 멤버를 호출하면 더 작은 클래스에서 해당 함수를 호출합니다.템플릿 클래스의 템플릿 가변 함수가 컴파일되지 않습니다.

#include <vector> 
#include <iostream> 

using namespace std; 

template <typename T, typename C> 
struct MyClass { 

    template <typename F, typename... A> 
    auto call_me(F func, A... args) { // pass in the function we want to call 
     return (mContainer.*func) (args...); // call the function supplied by 
     // the parameter on the private member data 
    } 

    C mContainer; // this will be private in my actual code 

}; 


int main() { 
    MyClass<int, std::vector<int> > test;; 

    cout << test.call_me(&std::vector<int>::size) << endl; // works 
    test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work 

    return 0; 
} 

이 내 실제 코드하지만 난 할 노력하고있어 작은 예는 아님을 유의하시기 바랍니다 : (? 혼란 오른쪽) 내가 여기에 작동하지 않는 예를 가지고 설명합니다. 보시다시피, 저는 size의 'Private'멤버 기능 (이 데모를 위해 여기 공개했습니다) vector 클래스의 멤버 함수를 MyClass 내부로 호출하려고합니다. 내가 컴파일러는 포장을위한 매개 변수가없는 때마다에만 작동합니다,하지만 난 삽입 기능 (압축하는 매개 변수가있는) 할 때, 컴파일러는 나에게의 오류 제공 : 이것은 동일

.\template.cpp: In function 'int main()': 
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)' 
    test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); 
                    ^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>] 
    auto call_me(F func, A... args) { // pass in the function we want to call 
      ^~~~~~~ 
.\template.cpp:10:10: note: template argument deduction/substitution failed: 
.\template.cpp:24:71: note: couldn't deduce template parameter 'F' 
    test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); 

오류 내 실제 생산 코드에 점점 매개 변수가 작동하지 않는 variadic 함수를 호출 해요,하지만 그 이상 줄 경우 같은 오류 메시지가 나타납니다. 이것은 Variadic 템플릿을 사용하려는 나의 첫 번째 시도이므로 권장 사항과 도움을 주시면 감사하겠습니다.

답변

6

여기서 문제는 insert이 오버로드 된 기능이라는 것입니다. 컴파일러는 템플릿 인수 공제에서 원하는 과부하를 알기위한 방법이 없으므로이를 시도하지 않습니다. 유형을 지정하기 위해 사용하려는 과부하 유형으로 함수를 형변환해야합니다. 즉, 또 다른 옵션은 조금 기능을 변경하고 완료를 원하는 것을 표현하는 람다을하는 것입니다

static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name) 

입니다 일반적으로

using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&); 
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4); 

과 같을 것이다. 컴파일러는 바로 함수의 엔트리 포인트 주소를 선택할 수 없기 때문에

template <typename T, typename C> 
struct MyClass { 

    template <typename F, typename... A> 
    auto call_me(F func, A... args) { // pass in the function we want to call 
     return func(mContainer, args...); // call the function supplied by 
     // the parameter on the private member data 
    } 

    C mContainer; // this will be private in my actual code 
}; 

int main() { 
    MyClass<int, std::vector<int> > test;; 

    test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4); 

    return 0; 
} 
+0

가 어떻게 그 일을 가겠어요 :

주면서 또한 (가 함수 객체있어) 작동? 인터넷 검색을 사용하면 static_cast를 사용할 수 없으므로 작동하지 않습니다. 'test.call_me (static_cast void (*) (std :: vector :: iterator, int)> (& std :: vector:: insert), test.mContainer.begin(), 4);'. 그것을 할 다른 방법이 있습니까? – Aryan

+0

@Aryan 방금 캐스트를 답변에 추가했습니다. – NathanOliver

+0

감사합니다. 그것을 할 수있는 더 아름다운 방법이 있습니까? 또는 적은 키 입력을 사용하는 무언가? – Aryan

0

은 기본적으로 당신이 해결되지 않은 오버로드 된 함수의 주소를 취할 수없는 것처럼 그것은 보일 것이다. 보통 함수 호출 중에 컴파일러는 오버로드 된 함수를 해결하지만, 사용자 또는 std :: bind()와 같은 템플릿을 사용하면 매개 변수가 주소를 가져 오는 함수가 아니라 템플릿 함수를 호출하는 데 사용되므로이 함수는 작동하지 않습니다.

using ftype = std::vector<int>::iterator(std::vector<int>::*) 
     (std::vector<int>::const_iterator, const std::vector<int>::value_type&); 
    test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works 
0

그것은 이런 종류의 일을 할 때 함수 객체에 거래를 쉽게 :

당신은 수동으로이 같은 과부하를 해결할 수 있습니다. 메소드 오버로드 문제를 컴파일러로 덜어줍니다.

#include <vector> 
#include <iostream> 

template <typename T, typename C> 
struct MyClass { 

    template <typename F, typename... A> 
    auto call_me(F func, A&&... args) -> decltype(auto) 
    { // pass in the function we want to call 
     return func(mContainer, std::forward<A>(args)...); // call the function supplied by 
     // the parameter on the private member data 
    } 

    C mContainer; // this will be private in my actual code 

}; 
/* 
* It's often easier to deal in function objects 
*/ 
struct insert 
{ 
    template<class Container, class...Args> 
    decltype(auto) operator()(Container& cont, Args&&...args) const 
    { 
     return cont.insert(std::forward<Args>(args)...); 
    } 
}; 

struct size 
{ 
    template<class Container, class...Args> 
    decltype(auto) operator()(Container& cont) const 
    { 
     return cont.size(); 
    } 
}; 

int main() { 
    MyClass<int, std::vector<int> > test;; 

    std::cout << test.call_me(size()) << std::endl; // works 
    test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work 

    // or lambdas 
    auto insert2 = [](auto& container, auto&&...args) -> decltype(auto) 
    { 
     return container.insert(std::forward<decltype(args)>(args)...); 
    }; 
    test.call_me(insert2, test.mContainer.begin(), 5); 


    return 0; 
} 
관련 문제