4

我正在嘗試編寫一個模板類的函數,它接受一個參數,該參數是大類的私有數據中的成員類的函數指針。當你調用該成員時,它會在較小的類上調用該函數。 (?混淆右)爲了證明,我這裏有一個非工作例如:模板類中的模板variadic函數不會編譯

#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」的成員函數(我已經在此處公開示範)vectorMyClass中的類。這隻能每當我有沒有參數編譯器進行解包,但是當我嘗試做插入功能(其參數解包),編譯器給我的錯誤:

.\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是一個重載函數。編譯器沒有試圖解決模板參數推導中需要的重載,因爲它無法知道。您必須將該函數強制轉換爲您要使用的重載類型,以便爲其指定類型。這看起來就像

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); 

一般是

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

另一種辦法是改變功能一點,並採取表達你想要做什麼拉姆達。這看起來就像

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 :: iterator,int)>(&std :: vector :: insert),test.mContainer.begin(),4);'。有沒有其他方法可以做到這一點? – Aryan

+0

@Aryan我剛剛添加演員到答案 – NathanOliver

+0

謝謝你,這工作。有沒有更美麗的方式來做到這一點?或者使用較少按鍵的東西? – Aryan

0

基本上你不能拿一個懸而未決的重載函數的地址,因爲編譯器將無法選擇正確的函數入口地址。在正常的函數調用期間,編譯器會解析重載的函數,但是像yours或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

它更容易做這種事情時,要處理的函數對象。它將方法重載的問題卸載到編譯器中。

Lambda表達式也行(他們是函數對象):

#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; 
}