2012-08-04 24 views
9

Tôi chỉ read ai đó gọi một lớp học với một constructor và một operator() một vị:Sự khác biệt giữa một Người Dự Bị và Người Làm Việc là gì?

// Example 
class Foo { 
    public: 
    Foo(Bar); 
    bool operator()(Baz); 
    private: 
    Bar bar; 
}; 

Tuy nhiên, tôi đã không nghe lời vị đang được sử dụng trong bối cảnh này trước đó. Tôi sẽ gọi một thứ như vậy là functor. Đối với tôi, một vị từ sẽ là một cái gì đó từ tên miền của logic chính thức.

Điều này đặt ra câu hỏi sau:

  • Đây có phải là một từ chung cho một cái gì đó giống như Foo?
  • Cả hai thuật ngữ được sử dụng thay thế cho nhau hay chúng có nghĩa là những thứ hơi khác nhau?
  • Hoặc
    • Liệu các kiểu trả về (bool so với cái gì khác) có cái gì để làm với nó?
    • Điều gì về số operator()const?

Trả lời

22

Functor là một thuật ngữ hỗ trợ toán tử () trong biểu thức (không có hoặc nhiều tham số), tức là một cái gì đó hoạt động như một hàm. Functor không nhất thiết phải là đối tượng của một số lớp với quá tải operator(). Tên hàm bình thường cũng là functors. Mặc dù trong một số ngữ cảnh, bạn có thể thấy thuật ngữ "functor" được sử dụng theo nghĩa hẹp hơn và độc quyền: chỉ các đối tượng lớp, chứ không phải các hàm bình thường.

A biến vị ngữloại cụ thể của hàm: một hàm đánh giá giá trị boolean. Giá trị này không nhất thiết phải là giá trị của loại bool, mà là giá trị của bất kỳ loại nào có ngữ nghĩa "boolean". Loại này nên được chuyển đổi hoàn toàn thành bool.

+3

Rất đẹp. Theo nghĩa chung, một functor là * bất kỳ đối tượng/tạo tác nào đại diện cho một hàm * theo thiết kế. Cho dù nó làm như vậy cú pháp và/hoặc với 'operator()' là đường. –

3

Lớp được hiển thị là một hàm thực hiện một biến vị ngữ.

A predicate là một hàm boolean.

Giới thiệu về operator() không phải là const tại đây: lý tưởng nhất là const, có.

+0

Lớp được hiển thị là một ví dụ. Tôi tự hỏi, nếu tất cả các vị ngữ là một functor. Những hạn chế nào được áp dụng, ngoài giá trị trả về là boolean? Một hàm miễn phí trả về 'bool' cũng là một biến vị ngữ? – bitmask

+0

Mọi biến vị ngữ là một hàm boolean, ở một mức trừu tượng phù hợp. Chắc chắn predicates trong Prolog không phải là C++ functors :-). Và do đó, có một chức năng tự do có thể được sử dụng như một vị từ. Nhìn vào câu hỏi bạn liên kết với (xin lỗi tôi đã không nhìn trước đó), nó không phải là một vị ngữ thuần túy, vì nó có một tác dụng phụ. Lý tưởng nhất là một vị ngữ không có tác dụng phụ, nó chỉ cho bạn biết liệu các đối số có đáp ứng một số điều kiện hay không, thường là chúng có một số mối quan hệ. –

2

Một vị là một loại đặc biệt của đối tượng chức năng. Xem điều này xuất sắc column bởi Nicolai Josuttis.Để báo giá:

Đối tượng hàm trả về giá trị Boolean là một biến vị ngữ. Đó là hầu như tất cả các hướng dẫn, sách và sách hướng dẫn đều viết về các biến vị ngữ của STL. Tuy nhiên, đây không phải là toàn bộ câu chuyện.

Tuy nhiên, có một yêu cầu bổ sung không may là không phải được đề cập trong bất kỳ sách hướng dẫn nào hoặc trong tiêu chuẩn C++: Một biến vị ngữ nên luôn trả về cùng một kết quả cho cùng một giá trị.

Hoặc, trong ngôn ngữ C++: Bạn nên khai báo operator() là một hàm thành viên liên tục (và không chơi trò chơi với thể thay đổi hoặc phôi). Vì lý do tương tự, bản sao của vị từ phải có cùng trạng thái làm bản gốc.

Lý do là thuật toán STL sẽ sao chép đối tượng chức năng xung quanh và việc sao chép không ảnh hưởng đến kết quả của việc áp dụng các đối tượng hàm.

template<typename Arg0> 
struct UnaryPredicate 
: 
    public std::function<bool(Arg0 const&)> 
{ 
    bool operator()(Arg0 const& a0) const 
    { 
     return // your code here 
    } 
}; 

template<typename Arg0, typename Arg1> 
struct BinaryPredicate 
: 
    public std::function<bool(Arg0 const&, Arg1 const&)> 
{ 
    bool operator()(Arg const& a0, Arg const& a1) const 
    { 
     return // your code here 
    } 
}; 
1

Như đã nói, một biến vị ngữ chỉ là người dùng cung cấp chỉ thị để phân tích cái gì đó sang trạng thái boolean. Vì vậy, bạn có thể có cùng một hai điều làm điều tương tự ...

struct is_odd 
{ 
    is_odd() : count(0); 
    bool operartor() (int i) const { ++count; return (i % 2) == 1; } 

private 
    int count; 
} 

Và ...

bool isOdd(int i) { return (i % 2) == 1; } 

Vì vậy, những gì là quá đặc biệt về các functor? Nó duy trì trạng thái nếu bạn muốn nó! Điều đó có nghĩa rằng trong khi hai dòng sau mã làm điều tương tự (giả sử v là một vector, với các giá trị 0-9) ...

for_each(v.begin(), v.end(), isOdd); //using C-style function pointer 

Và ...

is_odd fn = for_each(v.begin(), v.end(), is_odd); //using functor 

Chỉ với trường hợp sử dụng thứ hai bạn có thể sau đó gọi ...

int calls = fn.count; 

đó là bởi vì for_each (cũng như chức năng thuật toán STL khác) trả về functor nó được sử dụng ở cuối, vì vậy bây giờ trạng thái cuối cùng có thể được truy vấn.

Một điều thú vị khác cần lưu ý là trong trường hợp thứ hai, chúng tôi đang sử dụng cái được gọi là đối tượng "ẩn danh".

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