2013-03-27 38 views
19

tôi đã tự hỏi nếu điều này sẽ là một cách tiếp cận nhận vào văn bản callbacks:Passing và lưu trữ chức năng lambda như callbacks

callbacks Lưu trữ: định nghĩa

struct EventHolder { 
    std::function<void()> Callback; 
    EventTypes::EventType Type; 
}; 
std::vector<Events::EventHolder> EventCallbacks; 

Phương pháp:

void On(EventType OnEventType,std::function<void()>&& Callback) 
{ 
    Events::EventHolder NewEvent; 
    NewEvent.Callback=std::move(Callback); 
    NewEvent.Type=OnEventType; 
    EventCallbacks.push_back(std::move(NewEvent)); 
} 

kiện Binding :

Button->On(EventType::Click,[]{ 
    // ... callback body 
}); 

Câu hỏi lớn nhất của tôi là liên quan đến việc chuyển Gọi lại theo giá trị. Đây có phải là phương pháp hợp lệ không?

+0

Bạn có một số lỗi cú pháp ở đây. EventHolder trông giống như một struct nhưng được khai báo là enum. Ý của bạn là EventType là một enum? – Agentlien

+0

Agentlien, vâng đó là một cấu trúc và là một lỗi đánh máy nhỏ. Cảm ơn. – Grapes

+2

Nghĩ như vậy. :) Một mẹo cho tương lai: Hãy thử hoàn thành mã của bạn và thử biên dịch mã trước khi hoàn thành bài đăng. Bằng cách đó, bạn có cơ hội nhận được phản hồi chất lượng cao nhanh hơn trong khi câu hỏi vẫn còn mới.;) – Agentlien

Trả lời

10

Đây là cách tiếp cận hoàn toàn hợp lệ để lưu trữ trình xử lý sự kiện.

Tuy nhiên, tôi muốn chỉ ra một số chi tiết liên quan đến chữ ký của hàm của bạn để thêm gọi lại. Bạn lo lắng về việc chuyển nó theo giá trị so với tham chiếu. Trong ví dụ của bạn, bạn hiện có:

void On(EventType OnEventType,std::function<void()>&& Callback) 

Điều này là tốt, miễn là bạn sẽ chỉ bao giờ ràng buộc điều này với giá trị. Tuy nhiên, trừ khi có lý do cụ thể tại sao bạn muốn không cho phép, tôi khuyên bạn luôn có phương thức chấp nhận tham số theo giá trị hoặc tham chiếu lvalue và thêm phiên bản tham chiếu rvalue làm phần bổ sung nếu thấy cần thiết.

Không có một phương pháp mà phải mất một tài liệu tham khảo giá trị trái có nghĩa là mã của bạn hiện sẽ không biên dịch được đưa ra này:

std::function<void()> func([](){/*something clever*/}); 
// Do something necessary with func, perhaps logging or debug prints. 
Button->On(EventType::Click, func); 

Để đơn giản, bất cứ khi nào bạn đang lựa chọn như thế nào để vượt qua một giá trị, bạn chỉ có thể làm theo các hướng dẫn nói chung:

  • Nếu bạn cần bản sao hoặc có ý định sửa đổi giá trị được gửi vào mà không muốn thay đổi đối tượng thực tế được chuyển: vượt qua giá trị.
  • Nếu bạn dự định sửa đổi giá trị được gửi và muốn những thay đổi này ảnh hưởng đến đối tượng thực tế được chuyển: hãy chuyển theo tham chiếu.
  • Nếu bạn không muốn thay đổi đối tượng được chuyển, nhưng tin rằng có lợi khi tránh sao chép: vượt qua tham chiếu const.
  • Nếu bạn lấy tham số theo giá trị, tham chiếu hoặc tham chiếu const và tin rằng có tối ưu hóa có giá trị có thể đạt được bằng cách sử dụng kiến ​​thức rằng thông số đầu vào là tạm thời: cũng cho phép chuyển qua tham chiếu rvalue.
+0

Bài viết có liên quan [Muốn tốc độ? Vượt qua Giá trị.] (Http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/) từ Dave Abrahams – boycy

+0

@boycy Tôi đã cập nhật công thức của mình một chút để tạo ra trường hợp thảo luận trong bài viết dễ dàng hơn để xác định. – Agentlien

+0

Thật vậy @Agentlien, bài viết bổ sung cho câu trả lời của bạn và điền chi tiết hơn cho các khách truy cập khác. – boycy

1

Có. Các hàm là các con trỏ hàm nguyên tử hoặc các lớp trọng lượng nhẹ mà hàm tạo bản sao của chúng không có tác dụng phụ, vì vậy bản sao của chúng phải hoạt động như đối tượng gốc, vì vậy phương pháp này hoàn toàn ổn. Nhưng tại sao bạn truyền đối tượng theo giá trị và sau đó di chuyển nó vào vùng chứa ban đầu của bạn, bạn có thể chuyển tham chiếu và sau đó sao chép nó vào vùng chứa của bạn và có chức năng quá tải chấp nhận tham chiếu giá trị r (không nên quá quan trọng).

+0

Xin chào BigBoss, tôi đã cập nhật ví dụ của mình để bao gồm các tham chiếu RValue. – Grapes

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