2013-03-10 19 views
12

Ký hiệu cho std :: function khá đẹp khi so sánh với con trỏ hàm. Tuy nhiên, ngoài ra, tôi không thể tìm thấy một trường hợp sử dụng mà nó không thể được thay thế bằng con trỏ. Vì vậy, nó chỉ là cú pháp đường cho con trỏ chức năng?Có một trường hợp sử dụng cho std :: chức năng mà không được bao phủ bởi con trỏ chức năng, hoặc là nó chỉ cú pháp đường?

+4

Bất kỳ đối tượng nào có thể gọi không phải là chức năng? Functors stateful, lambdas, ràng buộc biểu thức ...? –

+1

std :: function là cú pháp đường cho tất cả các loại functors, không chỉ là con trỏ hàm. – nurettin

+2

@Xeo: câu trả lời trong câu hỏi này tốt hơn nhiều. –

Trả lời

24

std::function<> mang đến cho bạn khả năng đóng gói mọi loại đối tưởng callable, đó là gợi ý một cái gì đó chức năng không thể làm (mặc dù nó là sự thật rằng phi chụp lambdas có thể được chuyển đổi sang hoạt động con trỏ).

Để cung cấp cho bạn một ý tưởng về các loại linh hoạt nó cho phép bạn đạt được:

#include <functional> 
#include <iostream> 
#include <vector> 

// A functor... (could even have state!) 
struct X 
{ 
    void operator()() { std::cout << "Functor!" << std::endl; } 
}; 

// A regular function... 
void bar() 
{ 
    std::cout << "Function" << std::endl; 
} 

// A regular function with one argument that will be bound... 
void foo(int x) 
{ 
    std::cout << "Bound Function " << x << "!" << std::endl; 
} 

int main() 
{ 
    // Heterogenous collection of callable objects 
    std::vector<std::function<void()>> functions; 

    // Fill in the container... 
    functions.push_back(X()); 
    functions.push_back(bar); 
    functions.push_back(std::bind(foo, 42)); 

    // And a add a lambda defined in-place as well... 
    functions.push_back([]() { std::cout << "Lambda!" << std::endl; }); 

    // Now call them all! 
    for (auto& f : functions) 
    { 
     f(); // Same interface for all kinds of callable object... 
    } 
} 

Như thường lệ, thấy một live example here. Trong số những thứ khác, điều này cho phép bạn nhận ra số Command Pattern.

+0

Cảm ơn rất nhiều, ví dụ của bạn rất có ý nghĩa. –

+0

@static_rtti: OK, vui vì nó đã giúp :) –

+0

tại sao bạn không được phép giải thích về các chức năng thông thường? (Đó là người duy nhất mất tích '!') :-P –

7

std::function được thiết kế để thể hiện bất kỳ loại đối tượng có thể gọi nào. Có rất nhiều đối tượng có thể gọi được mà không thể được biểu diễn bằng bất kỳ cách nào bởi một con trỏ hàm.

  1. Một functor:

    struct foo { 
        bool operator()(int x) { return x > 5; } 
    }; 
    
    bool (*f1)(int) = foo(); // Error 
    std::function<bool(int)> f2 = foo(); // Okay 
    

    Bạn không thể tạo một thể hiện của foo và lưu nó trong một con trỏ bool(*)(int) chức năng.

  2. Một lambda với một lambda-chụp:

    bool (*f1)(int) = [&](int x) { return x > y; }; // Error 
    std::function<bool(int)> f2 = [&](int x) { return x > y; }; // Okay 
    

    Tuy nhiên, một lambda không có chụp có thể được chuyển đổi sang một con trỏ hàm:

    Kiểu đóng cửa cho một lambda- biểu thức không có lambda-capture có một hàm chuyển đổi const không rõ ràng công khai cho con trỏ tới hàm có cùng tham số và kiểu trả về như toán tử gọi hàm của kiểu đóng. Giá trị trả về bởi hàm chuyển đổi này sẽ là địa chỉ của hàm mà khi được gọi, có cùng tác dụng như gọi toán tử gọi hàm của loại đóng.

  3. thực hiện xác định giá trị có thể được gọi trở lại:

    bool foo(int x, int y) { return x > y; }; 
    
    bool (*f1)(int) = std::bind(&foo, std::placeholders::_1, 5); // Error (probably) 
    std::function<bool(int)> f2 = std::bind(&foo, std::placeholders::_1, 5); // Okay 
    

    std::bind 's giá trị trả về là một đối tượng có thể được gọi thực hiện xác định. Chỉ cách đối tượng đó có thể được sử dụng được quy định bởi tiêu chuẩn, không phải kiểu của nó.

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