2011-10-08 32 views
7

Tôi gặp vấn đề này làm phiền tôi. Tôi có lớp FSM mà phím sư để callbacksChức năng như thông số mẫu phát hành

class FSM 
{ 
public: 

typedef bool (FSM::*InCallback_t)(int); 
typedef std::map< std::string, InCallback_t > Table; 

// Since I would like to allow the user to register both functors and class member functions 
template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) > 
bool callback(int x) 
{ 
    return (Callback_t().*CallbackFunct_t)(x); 
} 

void addCallback(const std::string& iKey, InCallback_t iCallback) 
{ 
    _table.insert(std::make_pair(iKey, iCallback)); 
} 

    [ ... ] 

private: 
    Table _table; 
}; 

Và một số lớp callbacks

class CallbackBase 
{ 
public: 

    bool operator()(int x){ return doCall(x); } 

private: 
    virtual bool doCall(int x){ return true; } 
}; 


class Callback: public CallbackBase 
{ 
private: 
    bool doCall(int x) 
    { 
     std::cout << "Callback\n"; 
     return true; 
    } 
}; 

Bây giờ nếu vào chính tôi làm:

FSM aFSM; 
// OK 
aFSM.addCallback("one", &FSM::callback< CallbackBase, &CallbackBase::operator() >); 
// KO 
aFSM.addCallback("two", &FSM::callback< Callback, &Callback::operator() >); 

Cuộc gọi đầu tiên là tốt, trong trình biên dịch thứ hai than phiền:

Test.cpp: In function ‘int main(int, char**)’: 
Test.cpp:104:77: error: no matching function for call to ‘FSM::addCallback(const char [4], <unresolved overloaded function type>)’ 
Test.cpp:104:77: note: candidate is: 
Test.cpp:24:7: note: void FSM::addCallback(const string&, FSM::InCallback_t) 
Test.cpp:24:7: note: no known conversion for argument 2 from ‘<unresolved overloaded function type>’ to ‘FSM::InCallback_t’ 

Cũng lưu ý rằng những điều sau đây là tốt

typedef bool (Callback::*Function_t)(int); 
Function_t aFunction = &Callback::operator(); 
(Callback().*aFunction)(5); 

Bất kỳ ý tưởng nào? Cảm ơn trước sự giúp đỡ của bạn.

Simone

+2

Dường như lỗi trình biên dịch. : | – Nawaz

+0

Vâng tôi cũng nghĩ thế. Nó khá lạ – Simone

+0

Tôi cũng có một số vấn đề với việc sử dụng các hàm cơ sở (hoặc các toán tử) với một con trỏ thành viên của lớp dẫn xuất. Trong MSVC atleast, nó chỉ không hoạt động trong các mẫu. – Xeo

Trả lời

2

Bạn chưa xác định Callback :: operator(). Không có chức năng secound cho Callback chỉ là chức năng từ CallbackBase mà có một CallbackBase và int như một tham số! Đây là lý do tại sao trình biên dịch rên rỉ về "loại chức năng quá tải chưa được giải quyết".

Loại hàm được kế thừa là bool (CallbackBase :: * operator()) (int). Chức năng này có thể được tự động chuyển đổi thành một bool (Callback :: * operator()) (int) vì bạn luôn có thể áp dụng một cuộc gọi lại đến một hàm chỉ chấp nhận một CallbackBase. Đây là lý do tại sao các công trình sau đây - đó là một diễn viên tự động diễn ra ở đó.

typedef bool (Callback::*Function_t)(int); 
Function_t aFunction = &Callback::operator(); 

Vấn đề xảy ra với các mẫu loại trừ:

template< typename Callback_t, bool (Callback_t::*CallbackFunct_t)(int) > 
with: Callback_t = Callback, CallbackFunct_t = bool (CallbackBase::*CallbackFunct_t)(int) 

này không làm việc kể từ khi loại mà đưa qua Callback_t và các loại theo yêu cầu của con trỏ hàm không khớp nhau khi instanciating gọi lại chức năng. Bạn có thể giải quyết vấn đề với một diễn viên rõ ràng của con trỏ hàm đến (Callback :: * operator()) (int) trước khi loại khấu trừ diễn ra. Nếu bạn thay đổi chức năng gọi lại thành các phần sau, bạn không yêu cầu hai loại phải giống nhau và nó sẽ biên dịch mà không cần sử dụng.

template< typename Callback_t> 
bool callback(int x) 
{ 
    return Callback_t()(x); 
} 

Điều tôi không hiểu là lý do bạn thêm chức năng ảo. Sẽ không như sau làm như vậy, được đơn giản và dễ đọc hơn và thậm chí nhanh hơn (không có cuộc gọi chức năng ảo)? Hàm doCall sẽ được yêu cầu công khai.

template< typename Callback_t> 
bool callback(int x) 
{ 
    return Callback_t().doCall(x); 
} 

Một cải tiến khác sẽ làm cho hàm gọi lại tĩnh. Nó sẽ đơn giản hơn nhiều nếu các hàm doCall sẽ tĩnh - điều này sẽ làm cho hàm callback lỗi thời và sẽ tránh tạo ra một tạm thời để gọi doCall.

+0

Cảm ơn bạn đã trả lời. Một số bình luận. Về điểm nếu Callback :: operator() tồn tại. Nó tồn tại vì nó được thừa hưởng từ lớp cơ sở và trên thực tế ba dòng mã cuối cùng tôi đã đăng trong câu hỏi hoạt động đúng. Thật vậy, có vẻ như tôi có thêm một lỗi trình biên dịch. Có đúng là tôi có thể loại bỏ các điểm chức năng như tham số mẫu nhưng trong trường hợp đó tôi có thể xử lý đối tượng functor trong khi thực sự tôi muốn có linh hoạt hơn cho phép người dùng chỉ định các hàm thành viên trong trường hợp anh ta muốn có một lớp thực hiện tất cả các callbacks như các hàm thành viên. ... – Simone

+0

.. Về lý do tại sao tôi đã xác định toán tử() và doCall ảo. Đây là một mẫu được gọi là phương thức mẫu. Có trong ví dụ trên nó là vô ích nhưng bạn có thể tưởng tượng rằng trong toán tử() vào trong CallbackBase được thực hiện một số hoạt động trước và sau hoạt động được thực thi trước và sau khi gọi hàm gọi lại được thực hiện trong mỗi lớp dẫn xuất. Một ví dụ có thể lấy số liệu thống kê về thời gian thực hiện của doCall. – Simone

+0

@simone Tôi không tin vào lỗi trình biên dịch. Tôi đã cố gắng biên dịch mã của bạn trên gcc và trên studio trực quan với cùng một kết quả. Trong Visual Studio thông báo lỗi là: không thể chuyển đổi từ 'bool (__thiscall CallbackBase :: *) (int)' thành 'bool (__thiscall Callback :: * const) (int)'. Không có hàm Callback :: operator() nó chỉ gọi một từ lớp cơ sở. Sau đây không biên dịch trong bất kỳ trình biên dịch được đề cập: typedef void (Callback :: * func) (int); func f = & Callback :: toán tử(); –

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