2012-06-14 39 views
16

Tôi đang cố gắng tìm ra cách để có thể gán một con trỏ hàm cho hàm với số đối số khác nhau.C++: Hàm con trỏ hàm với số biến số đối số

Tôi có một vòng lặp while có một số hàm khác nhau như câu lệnh có điều kiện, vì vậy thay vì viết nhiều vòng lặp với chính xác cùng một mã bên trong tôi muốn có một con trỏ hàm. Tất cả các chức năng có định dạng bool f(...). Tôi nghĩ rằng một số mã sẽ minh họa tốt nhất ý của tôi:

int a, b, c, d; 
MyClass* my_class; 

typedef bool (MyClass::*my_fun_t)(); 
my_fun_t my_fun; 

if (condition1) 
    my_fun = &MyClass::function_one(); 
else if (condition2) 
    my_fun = &MyClass::function_two(a, b); 
else if (condition3) 
    my_fun = &MyClass::function_three(a, b, c); 
else if (condition4) 
    my_fun = &MyClass::function_four(a, b, c, d); 

while ((my_class->*my_fun)()) 
{ ... } 

Bây giờ điều này rõ ràng không hoạt động vì các hàm có chữ ký khác nhau. Có thể nào làm cho nó hoạt động theo cách tương tự? Là functoids cái gì tôi nên xem xét?

+0

Làm cách nào bạn biết cách áp dụng con trỏ hàm đó nếu bạn không biết cần bao nhiêu đối số? – mfontanini

+0

Lưu ý rằng cú pháp gán cho con trỏ hàm không hợp lệ, bạn đang * gọi * các hàm, lấy kết quả, lấy con trỏ tới bộ nhớ tạm thời của nó và gán * rằng * cho con trỏ hàm mà bạn đã khai báo trước đó. –

+0

Vâng tôi biết nó không phải là một cú pháp hợp lệ. Nó chỉ cho thấy ý tưởng. – jaho

Trả lời

7

Bạn có thể sử dụng std::function<>std::bind().

#include <functional> 

using std::placeholders::_1; 

typedef std::function<bool(MyClass&)> my_fun_t; 
my_fun_t my_fun; 

if (condition1) 
    my_fun = std::bind(&MyClass::function_one, _1); 
else if (condition2) 
    my_fun = std::bind(&MyClass::function_two, _1, a, b); 
else if (condition3) 
    my_fun = std::bind(&MyClass::function_three, _1, a, b, c); 
else if (condition4) 
    my_fun = std::bind(&MyClass::function_four, _1, a, b, c, d); 

while (my_fun(my_class)) { ... } 

Giả định bạn sẽ sử dụng C++ 11. Nếu bạn không thể sử dụng C++ 11 nhưng có thể sử dụng TR1, hãy thay thế tất cả std:: bằng std::tr1::. Ngoài ra còn có Boost implementation.

+1

Tuyệt vời, cảm ơn. Tôi không thể sử dụng C++ 11. Bất kỳ lý do để thích tr1 hơn tăng (mà tôi đang sử dụng anyway)? – jaho

+1

@Marian TR1 được xây dựng vào thư viện chuẩn, không phải là tăng. – kennytm

1

Tôi đang cố gắng tìm ra cách để có thể gán con trỏ hàm cho các hàm có số đối số khác nhau.

Bạn không thể. Con trỏ hàm cụ thể cho một chữ ký chức năng. Điều này hoàn toàn hợp lý: bạn sẽ gọi hàm như thế nào? (Vâng, C cho phép gọi các chức năng mà không chỉ định trong tuyên bố của họ có bao nhiêu thông số chức năng có, nhưng điều này không làm việc trong C++ vì nó subverts hệ thống kiểu.)

Are functoids cái gì tôi nên xem xét?

Thường có, nhưng chúng không giải quyết được vấn đề này.

+0

Hmm, nhưng chỉ 'chữ ký' của một hàm có đối số biến vẫn là duy nhất, phải không? Phần đối số biến '...' ít nhất chỉ là một ngụy trang của 'va_list' được sử dụng bên trong việc thực thi hàm. Việc gọi hàm như vậy thông qua một con trỏ hàm sẽ không (không nên) khác với cách gọi hàm như vậy theo cách thông thường (với một danh sách các biến đối số). –

+0

@ g-makulik Đối số biến hoạt động, nhưng đó là chữ ký cụ thể, nó không giống như ràng buộc với các chữ ký chức năng khác nhau. –

+0

Ahh, tôi thấy điểm của bạn !. Nhưng OP đã không đề cập đến ràng buộc một cách rõ ràng (có thể tôi đọc mã 'giả' của mình sai). Sử dụng định nghĩa giao diện (đa hình) nó vẫn có thể đạt được những gì OP muốn (dự định). –

3

Bạn muốn std::function, đối tượng hàm đa hình và std::bind để tạo đối tượng hàm bằng cách ràng buộc đối số với tham số của các hàm khác.

Nếu bạn không thể sử dụng C++ 11 thì boost::functionboost::bind tương đương, mặc dù hơi hạn chế hơn.

std::function<bool()> my_fun; 

if (condition1) 
    my_fun = std::bind(&MyClass::function_one, my_class); 
else if (condition2) 
    my_fun = std::bind(&MyClass::function_two, my_class, a, b); 
else if (condition3) 
    my_fun = std::bind(&MyClass::function_three, my_class, a, b, c); 
else if (condition4) 
    my_fun = std::bind(&MyClass::function_four, my_class, a, b, c, d); 

while (my_fun()) 
{ ... } 
+1

Nếu bạn có thể sử dụng C++ 11 thì bạn cũng có thể sử dụng hàm lambda và kéo các biến từ phạm vi từ vựng kèm theo. Cho dù bạn thích, tôi đoán vậy. – user268396

+0

@ user268396: Có thể. Trong thời gian này, tôi bị mắc kẹt với một trình biên dịch không hỗ trợ lambdas, vì vậy tôi không biết nhiều về chúng. –

+0

Giải pháp tăng cường đã làm việc cho tôi. Cảm ơn bạn. – jaho

4

này làm việc cho tôi:

#include <iostream> 
#include <cstdarg> 

using namespace std; 

class MyInterface 
{ 
public: 
    virtual bool func(int argc, ...) = 0; 
}; 

class MyImpl : public MyInterface 
{ 
public: 
    virtual bool func(int argc, ...); 
}; 

bool MyImpl::func(int argc, ...) 
{ 
    va_list varargs; 
    va_start(varargs,argc); 
    cout << "Arguments passed:" << endl; 
    for(int i = 0; i < argc; ++i) 
    { 
     // expect double values 
     double val = va_arg(varargs,double); 
     cout << val << endl; 
    } 
    va_end(varargs); 
    return true; 
} 

typedef bool (MyInterface::*MyFunc)(int, ...); 

int main() { 

    MyImpl impl; 
    MyInterface* interface = &impl; 
    MyFunc pfunc = &MyInterface::func; 

    if(!(interface->*pfunc)(2,double(3.14),double(2.72))) 
    { 
     return 1; 
    } 
    return 0; 
} 

Output:

Arguments passed: 
3.14 
2.72 

Rõ ràng bạn có thể khai báo và sử dụng con trỏ hàm cho các chức năng (member-) sử dụng đối số biến.

Các vấn đề liên quan