cách boost :: chức năng và boost :: ràng buộc công việc


83

Tôi không thích có các hộp ma thuật nằm rải rác khắp mã của tôi ... chính xác thì hai lớp này hoạt động như thế nào để cho phép về cơ bản bất kỳ hàm nào được ánh xạ tới một đối tượng hàm ngay cả khi hàm <> có một tham số hoàn toàn khác với tham số mà tôi chuyển tới boost::bind

Nó thậm chí hoạt động với các quy ước gọi khác nhau (nghĩa là các phương thức thành viên nằm __thiscalldưới VC, nhưng các hàm "bình thường" nói chung __cdeclhoặc __stdcallcho những hàm cần tương thích với C.



1
không thực sự - câu hỏi này là về ràng buộc và chức năng
1800 INFORMATION

Có và do đó, điều đó vẫn để lại câu hỏi về cách có thể liên kết bản đồ void MyClass: DoSomething (std :: string str, int number) để boost :: function <void (int)> thông qua bind (& MyClass :: DoSomething, chẳng hạn, "Xin chào Thế giới ", _1)
Fire Lancer

2
20.000 lượt truy cập con bò thần thánh này cần phải có trên trang đầu thúc đẩy !
unixman83

Câu trả lời:


96

boost::functioncho phép bất cứ thứ gì có operator()chữ ký phù hợp được ràng buộc dưới dạng tham số và kết quả của ràng buộc của bạn có thể được gọi với một tham số int, vì vậy nó có thể được liên kết với function<void(int)>.

Đây là cách nó hoạt động (mô tả này áp dụng cho std::function):

boost::bind(&klass::member, instance, 0, _1) trả về một đối tượng như thế này

struct unspecified_type
{
  ... some members ...
  return_type operator()(int i) const { return instance->*&klass::member(0, i);
}

trong đó dấu return_typeintđược suy ra từ chữ ký của klass::member, và con trỏ hàm và tham số ràng buộc trên thực tế được lưu trữ trong đối tượng, nhưng điều đó không quan trọng

Hiện nay, boost::function không thực hiện bất kỳ kiểm tra kiểu nào: Nó sẽ lấy bất kỳ đối tượng nào và bất kỳ chữ ký nào bạn cung cấp trong tham số mẫu của nó và tạo một đối tượng có thể gọi theo chữ ký của bạn và gọi đối tượng. Nếu điều đó là không thể, đó là lỗi biên dịch.

boost::function thực sự là một đối tượng như thế này:

template <class Sig>
class function
{
  function_impl<Sig>* f;
public:
  return_type operator()(argument_type arg0) const { return (*f)(arg0); }
};

nơi return_typeargument_typeđược trích xuất từ ​​đâu Sigfđược phân bổ động trên heap. Điều đó cần thiết để cho phép các đối tượng hoàn toàn không liên quan với các kích thước khác nhau liên kết với boost::function.

function_impl chỉ là một lớp trừu tượng

template <class Sig>
class function_impl
{
public:
  virtual return_type operator()(argument_type arg0) const=0;
};

Lớp thực hiện tất cả công việc, là một lớp cụ thể có nguồn gốc từ boost::function. Có một cho mỗi loại đối tượng mà bạn chỉ địnhboost::function

template <class Sig, class Object>
class function_impl_concrete : public function_impl<Sig>
{
  Object o
public:
  virtual return_type operator()(argument_type arg0) const=0 { return o(arg0); }
};

Điều đó có nghĩa là trong trường hợp của bạn, nhiệm vụ tăng cường chức năng:

  1. khởi tạo một kiểu function_impl_concrete<void(int), unspecified_type>(tất nhiên đó là thời gian biên dịch)
  2. tạo một đối tượng mới thuộc loại đó trên heap
  3. gán đối tượng này cho thành viên f của hàm boost ::

Khi bạn gọi đối tượng hàm, nó sẽ gọi hàm ảo của đối tượng triển khai của nó, đối tượng này sẽ hướng lệnh gọi đến hàm ban đầu của bạn.

KHUYẾN CÁO: Lưu ý rằng những cái tên trong phần giải thích này được cố tình tạo ra. Bất kỳ điểm nào giống với người thật hoặc nhân vật ... bạn biết điều đó. Mục đích là để minh họa các nguyên tắc.


vậy nội dung của struct unsecified_type (tức là mã trong hàm operator ()) được tạo cơ bản từ các đối số trong quá khứ để boost :: bind trên cơ sở từng trường hợp để cho phép bất kỳ sự kết hợp và số lượng đối số nào không?
Fire Lancer

1
Không, có mẫu của nhà điều hành () có thể xử lý tất cả các arities (và đối số mẫu khác nhau xử lý các kết hợp)
jpalecek

Trong khối mã cuối cùng, nó ghi: arg0) const=0 { return...... Tôi chưa bao giờ thấy điều đó trước đây. Tôi đã tìm thấy một ví dụ không hoạt động trong một diễn đàn trong đó một thông báo tiếp theo được liên kết với C ++ faq giải thích rằng một hàm ảo thuần túy có thể có phần thân, nhưng tôi không thể lấy bất kỳ mã nào để biên dịch bằng cú pháp như vậy (clang & gcc).
Brian Vandenberg

Tôi nên làm rõ câu hỏi của mình một chút: Một ảo thuần túy có thể được cung cấp một phần thân khi được khai báo =0;với phần thân được đưa ra sau (ví dụ void Base::Blah() { /* ... */ }:) ... Tôi đang hỏi cụ thể về ký hiệu được sử dụng ở trên; Tôi đoán đó chỉ là lỗi đánh máy.
Brian Vandenberg

@BrianVandenberg: Tôi nghĩ nó tuân theo tiêu chuẩn, mặc dù khá vô nghĩa.
Mooing Duck,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.