2015-01-26 16 views
10

Tại sao một người thích gọi std :: ref thay vì không gọi nó?STD :: ref hữu ích cho chức năng này là gì?

template<class F, class...Ts> F for_each_arg(F f, Ts&&...a) { 
    return (void)initializer_list<int>{(ref(f)((Ts&&)a), 0)...}, f; 
    // why not return (void)initializer_list<int>{(f((Ts&&)a), 0)...}, f; 
} 
+2

Không cần thiết. https://twitter.com/ericniebler/status/559798611991879684 – inf

Trả lời

17

std::reference_wrapper::operator() thực hiện một chút "ma thuật" trong một số trường hợp ngoài cuộc gọi hàm trực tiếp. ảnh hưởng của nó được quy định như (trích dẫn N4296 [refwrap.invoke]):

template <class... ArgTypes> 
result_of_t<T&(ArgTypes&&...)> 
operator()(ArgTypes&&... args) const; 

Returns: INVOKE(get(), std::forward<ArgTypes>(args)...). (20.9.2)

nơi get() trả về tham chiếu đến những gì reference_wrapper kết thúc tốt đẹp. INVOKE được mô tả trong 20.9.2 [func.require]:

Xác định INVOKE(f, t1, t2, ..., tN) như sau:

(1,1) - (t1.*f)(t2, ..., tN) khi f là một con trỏ tới một hàm thành viên của một lớp Tt1 là một đối tượng thuộc loại T hoặc tham chiếu đến đối tượng thuộc loại T hoặc tham chiếu đến đối tượng thuộc loại bắt nguồn từ T;

(1,2) - ((*t1).*f)(t2, ..., tN) khi f là một con trỏ tới một hàm thành viên của một lớp Tt1 không phải là một trong những loại được mô tả trong mục trước;

(1,3) - t1.*f khi N == 1f là một con trỏ đến dữ liệu thành viên của một lớp Tt1 là một đối tượng kiểu T hoặc một tham chiếu đến một đối tượng kiểu T hoặc một tham chiếu đến một đối tượng của một loại có nguồn gốc từ T;

(1,4) - (*t1).*f khi N == 1f là một con trỏ đến dữ liệu thành viên của một lớp Tt1 không phải là một trong những loại được mô tả trong mục trước;

(1.5) - f(t1, t2, ..., tN) trong tất cả các trường hợp khác.

Kết quả của việc gọi ref(f) thay vì chỉ đơn giản là f là con trỏ-to-viên-chức năng và con trỏ-to-viên-dữ liệu có thể "gọi là" với một con trỏ đối tượng/tài liệu tham khảo phù hợp theo tham số. Ví dụ,

struct A { void foo(); }; 
struct B : A {}; 
struct C : B {}; 
for_each_arg(&A::foo, A{}, B{}, C{}, std::make_unique<A>()); 

sẽ gọi foo trên A, BC đối tượng tạm thời và các đối tượng tổ chức tại unique_ptr (DEMO). Tại sao một người sẽ thích để sử dụng ref(f) hơn f rõ ràng sẽ phụ thuộc vào ngữ cảnh trong đó một người đang sử dụng for_each_arg.

+0

Thú vị, nhưng một tính năng kỳ diệu khác của 'std :: reference_wrapper'. Tự hỏi tại sao Eric Niebler lại coi nó là không cần thiết. – inf

+0

@bamboon Khó nói mà không cần thêm ngữ cảnh.Tôi sẽ suy đoán rằng 'ref()' thêm 5 ký tự nữa và loại bỏ nó sẽ dẫn đến mã ngắn hơn cho mục đích chơi mã. – Casey

+0

Tại sao 'auto f = std :: ref (& A :: foo);' không thành công, nhưng 'auto f = & A :: foo; auto f2 = std :: ref (f) 'thành công? – Barry

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