2012-03-19 118 views
17

考慮以下代碼:通用成員函數指針作爲模板參數

#include <iostream> 
using namespace std; 

class hello{ 
public: 
    void f(){ 
     cout<<"f"<<endl; 
    } 
    virtual void ff(){ 
     cout<<"ff"<<endl; 
    } 
}; 

#define call_mem_fn(object, ptr) ((object).*(ptr)) 

template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){ 
    cout<<"hello"<<endl; 
    call_mem_fn(obj, ptr_to_mem)(); 
} 

int main(){ 
    hello obj; 
    proxycall<&hello::f>(obj); 
} 

當然這不會在第16行編譯,因爲編譯器不知道什麼RCArgs,是。但是還有另外一個問題:如果試圖ptr_to_mem前右定義這些模板參數,他遇到這種糟糕的情況:

template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)> 
          // ^variadic template, but not as last parameter! 
void proxycall(C& obj){ 
    cout<<"hello"<<endl; 
    call_mem_fn(obj, ptr_to_mem)(); 
} 

int main(){ 
    hello obj; 
    proxycall<void, hello, &hello::f>(obj); 
} 

出人意料的是,G ++不抱怨Args不是在模板列表中的最後一個參數,但無論如何它不能將proxycall綁定到正確的模板函數,只是指出這是一個可能的候選人。

任何解決方案?我最後的手段是將成員函數指針作爲參數傳遞,但是如果我可以將它作爲模板參數傳遞,它將更適合於我的其他代碼。

編輯: 如一些人所指出的,例如似乎毫無意義,因爲proxycall不會傳遞任何參數。在我正在處理的實際代碼中,這不是真的:參數是從一個Lua棧的一些模板技巧中獲取的。但是這部分代碼與問題無關,而且相當冗長,所以我不會在這裏粘貼它。

+0

在我看來,在這種情況下你實際上並不需要可變參數模板參數。 'proxycall()'不會將任何參數傳遞給成員函數指針調用,所以使用可變參數模板參數似乎會使問題變得比它需要的更困難。 – 2012-03-19 23:23:14

+1

這沒有意義。你的「call_mem_fn」#define實際上並不提供參數。所以如果Args只是空的,它就不會起作用。那麼你如何期待這個功能起作用呢? – 2012-03-19 23:25:52

+0

問題中的代碼僅僅是一個例子。實際的代碼將處理具有任意數量參數的函數,並且將從其他地方(即,Lua棧)中檢索它們。獲取參數的元編程膠水代碼已經工作,我不會在這裏粘貼它,因爲它很長。 – 2012-03-19 23:39:37

回答

32

你可以嘗試這樣的事:

template <typename T, typename R, typename ...Args> 
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args) 
{ 
    return (obj.*mf)(std::forward<Args>(args)...); 
} 

用法:proxycall(obj, &hello::f);

或者,使PTMF成模板參數,儘量專業化:

template <typename T, T> struct proxy; 

template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)> 
struct proxy<R (T::*)(Args...), mf> 
{ 
    static R call(T & obj, Args &&... args) 
    { 
     return (obj.*mf)(std::forward<Args>(args)...); 
    } 
}; 

用法:

hello obj; 

proxy<void(hello::*)(), &hello::f>::call(obj); 

// or 

typedef proxy<void(hello::*)(), &hello::f> hello_proxy; 
hello_proxy::call(obj); 
+0

我總是忘記,當我遇到功能模板的麻煩時,班級模板就是我的救生艇。 – 2012-03-19 23:53:58

+0

@LorenzoPistone:通常你用類模板實現你的魔法和使用專業化,並在最後加少許類型推導*功能*模板,所以你不必拼出模板參數。不過,在這種情況下,我並不知道這有什麼用處,但也許這足以給你一個想法。 – 2012-03-19 23:55:38

+1

不要忘記處理'const'成員函數。 (但是,如果你決定不與'volatile'或'常量volatile'打擾,我不會抱怨。) – aschepler 2012-03-20 00:23:09

相關問題