2016-06-15 15 views
11

tôi đã viết chức năng bậc cao như thế này:đối tượng hoàn hảo chuyển tiếp có thể được gọi trong các chức năng bậc cao

template<typename F, typename... Args> 
void doStuff(F f, Args&&... args) 
{ 
    // ... 
    f(std::forward<Args>(args)...); 
    // ... 
} 

Hoặc có thể thay thế F f với F&& f.

Nhưng sau khi tôi biết về các vòng loại ref (ouch), mọi thứ trở nên phức tạp. Hãy tưởng tượng một lớp functor:

struct Foo { 
    void operator()(...) &; 
    void operator()(...) &&; 
}; 

Sau đó triển khai trước đây của tôi về doStuff sẽ chỉ bao giờ gọi phương thức &, kể từ khi thông số luôn lvalues.

Tôi nghĩ rằng cách giải quyết này là để thực hiện doStuff như thế này:

template<typename F, typename... Args> 
void doStuff(F&& f, Args&&... args) 
{ 
    // ... 
    std::forward<F>(f)(std::forward<Args>(args)...); 
    // ... 
} 

Đây cũng là cách std::result_ofpossibly implemented. Điều tôi muốn biết là, có bất kỳ hạn chế nào đối với việc triển khai này không, tức là, tôi có nên thay thế tất cả các triển khai HOF của mình bằng không?

+0

Có vẻ tốt miễn là 'f' sẽ không được sử dụng lại sau đó. Có thể 'toán tử()' sẽ có một số tác dụng phụ có thể thay đổi các thành viên bên trong (di chuyển trên các thành viên bên trong) của 'f' (nếu có). Tôi không chắc chắn mặc dù, đã không nghĩ rằng nó thông qua ... Câu hỏi hay. – Arunmu

+0

@Arunmu Nếu (1) phương thức bị quá tải trên các vòng loại, và (2) người gọi vượt qua hàm functor dưới dạng giá trị, chúng tôi có đủ lý do để tin rằng người gọi có ý định gọi phiên bản '&&'. Trong trường hợp đó, có lẽ là hợp lý để hoàn thiện mọi sự xuất hiện của 'f' trong' doStuff' ... tôi nghĩ vậy. –

+1

Tôi không thấy bất kỳ vấn đề nào với 'forward (f)' miễn là không sử dụng 'f' lần nữa trong' doStuff' – Praetorian

Trả lời

0

std::forward là giá trị r có điều kiện, và điểm là như thường lệ để ăn cắp ruột từ các đối tượng chết. Không có sự khác biệt giữa functors và các đối tượng khác về mặt này. Phía dưới cũng giống như bất kỳ việc sử dụng nào của std::forward; nếu bạn không chuẩn bị để ăn cắp những can đảm, bạn không nên.

#include <iostream> 
#include <vector> 

struct Foo { 
    std::vector<int> vec = {1,2,3}; 
    std::vector<int>& operator()(...) & { 
     return vec; 
    } 
    std::vector<int> operator()(...) && { 
     return std::move(vec); 
     // Clearly, don't rely on 'vec' here... 
    } 
}; 

Foo getFoo(){ 
    return {}; 
} 

int main() { 
    auto foo = getFoo(); 
    auto vec1=foo(); 
    auto vec2=getFoo()(); 
} 

Rõ ràng, không làm những việc như thế này:

auto vec3 = std::move(foo)(); 
vec4 = foo(); 

vì những lý do tương tự.

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