2013-09-03 87 views
5

Ngắn câu chuyện, có cách nào đơn giản/được định nghĩa để xử lý các đối tượng hàm/lambdas và các hàm thành viên theo cách được sắp xếp hợp lý không?Sử dụng lệnh std :: function/mem_fn trong C++ 11 với các hàm thành viên

Nếu tôi hiểu đúng, nếu tôi sử dụng std :: mem_fn, tôi cần phải vượt qua một đối tượng của loại chính xác cho cuộc gọi chức năng, tức là

Object o; 
ftncall std::mem_fun(&Object::function); 
ftncall(o); 

Lý tưởng nhất, sẽ có một số cách để 'đính kèm 'o đối với đối tượng chức năng đó, có thể là std::weak_ptr, vì vậy chúng tôi biết nếu o đã bị xóa. Ví dụ: nếu có cách để làm điều gì đó mơ hồ như thế này:

Object o; 
ftncall std::mem_fn(&Object::function, o); // Or maybe std::mem_fn<Object> 
ftncall(); 

Bây giờ, rõ ràng, điều này không tồn tại (theo kiến ​​thức của tôi). Có cách nào để bọc std :: mem_fn theo cách như vậy mà tôi không mất tính tổng quát (và độc đáo) của std :: mem_fn, nhưng có thể 'đính kèm' o, VÀ vẫn chơi độc đáo với các loại chức năng khác, như std :: function? Lý tưởng nhất, tôi vẫn có thể sử dụng operator() theo cách mà tôi làm với std :: function.

Hiện nay các giải pháp tốt nhất mà tôi có thể nghĩ đến là một lớp trông như thế này:

template<class T> 
class MemFunWrapper { 
public: 
    MemFunWrapper(T* t, std::mem_fun funct) : m_t(t), m_function(funct) {} 

    std::mem_fun operator*() { return m_function; } 
    T* get() { return m_t; } 
private: 
    T* m_t; 
    std::mem_fun m_function; 
} 

Sau đó, bạn có thể sử dụng nó thusly:

(*MemFunWrapper)(MemFunWrapper->get(), args...); 

Nhưng điều đó có vẻ khá khó sử dụng đối với tôi. Ngoài ra, tôi sẽ phải tạo ra một lớp tương đương cho std :: chức năng cho rằng có thể sử dụng theo cách tương tự, và điều đó có vẻ ngớ ngẩn vì tôi đã có thể chỉ sử dụng std :: function. Lý tưởng nhất, tôi cũng có thể sử dụng sản phẩm cuối cùng mà không biết liệu tôi có đang gọi chức năng thành viên hay chức năng thông thường hay không. Tôi biết tôi đang hỏi rất nhiều - mọi hướng sẽ hữu ích. Cảm ơn nhiều!

Trả lời

10

gì bạn đang tìm kiếm là std :: ràng buộc thay vì std :: mem_fn:

#include <iostream> 
#include <functional> 

struct Object 
{ 
    void member() 
    { 
    std::cout << "yay!" << std::endl; 
    } 
}; 

int main() 
{ 
    Object o; 
    auto fn = std::bind(&Object::member, o); 
    fn(); 
} 

FWIW: Có một proposal cho thêm một tình trạng quá tải để std :: mem_fn tiếp nhận đối tượng để đưa vào C++ 14.

+1

Tại sao cảm ơn bạn - bạn có thể vừa hoàn thành tất cả hy vọng và ước mơ của mình! –

+0

Không nên là dòng 'auto fn = std :: bind (& Object :: member, o);' được 'tự động fn = std :: bind (& Object :: member, &o);', nhớ đối số thứ hai là 'std: : bind' –

+0

Phụ thuộc vào ý định của bạn Cả hai đều hữu ích trong các hoàn cảnh khác nhau – goji

8

Trong C++ 11, tôi thường tìm thấy điều này là dễ nhất thực hiện với lambdas:

std::shared_ptr<Object> o; 
auto ftncall = [o](){ if (o) o->function(); } 
ftncall(); 

Nếu bạn cần loại tẩy xoá, chỉ cần nhét nó vào một std::function<void()>.

Lambdas trong C++ 11 có thể thực hiện nhiều công việc giống như bind mà không phải dựa vào chức năng thư viện để làm điều đó, và cá nhân tôi thấy chúng dễ đọc hơn nhiều.

Có một số trường hợp mà bind có thể thực hiện tốt hơn trong C++ 11, nhưng chúng là trường hợp góc tại thời điểm này (trong C++ 1y, nhiều góc hơn cũng sẽ bị cắt).

+0

Chỉ cần tò mò, bạn có thể chỉ cho tôi một số ví dụ 'std :: bind' tốt hơn trong C++ 11 không? Tôi suy nghĩ một lúc nhưng tôi có thể không liên quan đến việc thiếu lambda đa hình? – Sungmin

+1

@Sungmin 'bind' hỗ trợ chuyển tiếp hoàn hảo, trong khi lambdas thì không.Lambdas không thể đa hình, trong khi 'bind' có thể. Một lambda có kiểu trả về cố định: 'bind' có thể khác nhau, nếu bạn truyền nó cho một hàm functor với nhiều tình trạng quá tải. 'bind' hỗ trợ gói functors variardic và variardic còn lại, lambdas thì không. 'bind' có thể được gọi trong các ngữ cảnh không được đánh giá, như 'decltype', hữu ích cho' auto foo() -> decltype (bind (blah)) ': trong khi kiểu này là obtuse, nó không phải là ma thuật như labmda. Đó là những thứ tôi có thể nghĩ ra khỏi đỉnh đầu. Hơn một nửa trong số họ đã biến mất trong C++ 1y. – Yakk

+0

Cũng vô cùng hữu ích - điều này có vẻ 'dễ dàng hơn' như bạn nói, nhưng thật tuyệt khi biết tôi vẫn cần sử dụng 'bind' nếu tôi sẽ sử dụng các hàm đa hình - có lẽ là các tình huống có thể gây ra vấn đề cho tôi ít nhất. –

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