2012-05-07 30 views
5

Tôi đã điều sau đây:Xác định một hàm thành viên như một callback trong C++ 11

typedef std::function<bool (const std::string&)> SomethingCoolCb; 

class ClassA 
{ 
public: 
    void OnSomethingCool(const SomethingCoolCb& cb) 
    { 
     _cb = cb; 
    } 

private: 
    SomethingCoolCb _cb; 
}; 

class ClassB 
{ 
public: 
    ClassB(); 
    bool Juggle(const std::string& arg); 

private: 
    ClassA _obj; 
}; 

và tôi muốn xác định ClassB :: Juggle() chức năng thành viên như gọi lại để ClassB :: _ obj. Sẽ cách thích hợp để làm điều đó trong C++ 11 được (trong constructor ClassB của):

ClassB::ClassB() 
{ 
    _obj.OnDoSomethingCool(
     [&](const std::string& arg) -> bool 
     { 
      return Juggle(arg); 
     }); 
} 

Từ những gì tôi hiểu, trình biên dịch sẽ làm cho một đối tượng std :: chức năng ra của mã lambda trên. Vì vậy, khi gọi lại được gọi, nó sẽ gọi thành phần std :: function :: operator() và sau đó nó sẽ gọi ClassB :: Juggle() thay vì gọi ClassB :: Juggle() trực tiếp. Trừ khi tôi nhầm lẫn về những gì xảy ra dưới sự che chở, tất cả dường như không hiệu quả chút nào. Có cách nào tốt hơn?

+2

Hãy coi chừng việc chụp 'this' trong lambda (như trong ví dụ của bạn) không hoạt động tốt với Visual Studio 2010. –

Trả lời

6

Chỉ sử dụng std::function nếu bạn thực sự cần chức năng đa hình. Nếu không, hãy biến nó thành một mẫu.

Để điều chỉnh hàm thành viên để sử dụng hàm functor std::mem_fn và sau đó bind đối tượng cho đối số đầu tiên, hàm functor kết quả có thể dùng làm gọi lại của bạn.

mẫu:

#include <string> 
#include <functional> 

template<typename F> 
class ClassA 
{ 
public: 
    ClassA(F f) : _cb(f) {} 

private: 
    F _cb; 
}; 

class ClassB 
{ 
public: 
    ClassB() 
    : _obj(std::bind(&ClassB::Juggle, this, 
        std::placeholders::_1)) 
    {} 
    bool Juggle(const std::string& arg) {return true;} 
private: 
    ClassA<decltype(std::bind(
         std::declval<bool (ClassB::*)(const std::string&)>() 
         , std::declval<ClassB*>() 
         , std::placeholders::_1 
        )) > _obj; 
}; 

int main() 
{ 
    ClassB b; 
    return 0; 
} 

phụ bước này chi phí của chức năng với chi phí là khủng khiếp xấu xí.

+0

Cú pháp bind() luôn khiến tôi hơi queezy với trình giữ chỗ _1, _2, _3, v.v. các thông số và những gì không. Tôi đã thấy rằng bây giờ C++ có lambdas, bind() đã lỗi thời. Nhưng vì bind() nằm ngoài Boost và bây giờ là một phần của tiêu chuẩn, có lẽ tôi đã nhầm lẫn với giả định đó. –

+2

@ArcadioAlivioSincero 'bind' vẫn có thể hữu ích. Đôi khi nó cũng ngắn hơn. Tôi đã cập nhật ví dụ về bước bên 'hàm' với một chút thủ đoạn. – pmr

+1

Gọi lại thường là một nơi tốt để sử dụng 'std :: function <>' s cho tính linh hoạt (xem xét * chức năng * có thể được sử dụng để đăng ký * bất kỳ loại * gọi lại nào, bạn cần thứ gì đó đồng bộ để lưu trữ) –

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