2012-03-19 14 views
17

xem xét mã này:generic function pointer viên làm mẫu tham số

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

Tất nhiên điều này sẽ không biên dịch tại dòng 16, bởi vì trình biên dịch không biết những gì R, CArgs, đang có. Nhưng có một vấn đề khác: nếu một cố gắng để xác định các tham số mẫu ngay trước ptr_to_mem, ông chạy vào tình huống xấu này:

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

Đáng ngạc nhiên, g ++ không phàn nàn về Args không phải là tham số cuối cùng trong danh sách mẫu, nhưng dù sao nó không thể liên kết proxycall với chức năng mẫu phù hợp, và chỉ cần lưu ý rằng đó là một ứng viên có thể.

Bất kỳ giải pháp nào? Phương pháp cuối cùng của tôi là chuyển con trỏ hàm thành viên làm đối số, nhưng nếu tôi có thể chuyển nó thành tham số mẫu, nó sẽ phù hợp hơn với phần còn lại của mã của tôi.

EDIT: như một số đã chỉ ra, ví dụ có vẻ vô nghĩa vì proxycall sẽ không vượt qua bất kỳ đối số nào. Điều này là không đúng trong mã thực tế tôi đang làm việc trên: các đối số được lấy với một số thủ thuật mẫu từ một ngăn xếp Lua. Nhưng phần mã đó không liên quan đến câu hỏi, và khá dài, vì vậy tôi sẽ không dán nó ở đây.

+0

Dường như với tôi rằng bạn không thực sự cần các tham số mẫu của vectơ trong trường hợp này. 'proxycall()' sẽ không chuyển bất kỳ đối số nào tới lời gọi con trỏ hàm thành viên, vì vậy việc sử dụng các tham số mẫu của Denisdic xuất hiện để làm cho vấn đề khó khăn hơn nó cần. –

+1

Điều này không có ý nghĩa. "Call_mem_fn" #define của bạn không thực sự cung cấp thông số. Vì vậy, nó sẽ không hoạt động nếu Args là bất cứ điều gì nhưng trống rỗng. Vì vậy, làm thế nào để bạn mong đợi điều này để thực sự hoạt động? –

+0

Mã trong câu hỏi chỉ là một ví dụ. Mã thực tế sẽ xử lý các hàm với một số đối số tùy ý, và chúng sẽ được lấy ra từ một nơi khác (cụ thể là một ngăn xếp Lua). Mã keo siêu lập trình tải các đối số đã hoạt động, tôi sẽ không dán nó ở đây vì nó dài. –

Trả lời

32

Bạn có thể thử một cái gì đó như thế này:

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

Cách sử dụng: proxycall(obj, &hello::f);

Ngoài ra, để làm cho PTMF thành một mẫu tranh luận, hãy thử chuyên môn:

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

Cách sử dụng:

hello obj; 

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

// or 

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

Tôi luôn luôn quên rằng khi tôi gặp rắc rối với các mẫu chức năng, các mẫu lớp là xuồng cứu sinh của tôi. –

+0

@LorenzoPistone: Thông thường bạn thực hiện phép thuật của mình với một mẫu lớp và sử dụng chuyên môn hóa, và cuối cùng bạn thêm một chút mẫu * chức năng * mẫu để bạn không phải đánh vần các tham số mẫu. Trong trường hợp này, mặc dù, tôi không thực sự biết làm thế nào điều này sẽ giúp, nhưng có lẽ điều này là đủ để cung cấp cho bạn một ý tưởng. –

+1

Đừng quên đối phó với các hàm thành viên 'const'. (Nhưng nếu bạn quyết định không bận tâm với 'volatile' hoặc 'const volatile', tôi sẽ không phàn nàn.) – aschepler