2015-01-26 13 views
10

Dlaczego wolelibyśmy wywoływać std :: ref zamiast go w ogóle nie wywoływać?Do czego służy funkcja std :: ref w tej funkcji?

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

To niepotrzebne. https://twitter.com/ericniebler/status/559798611991879684 – inf

Odpowiedz

17

std::reference_wrapper::operator() wykonuje kawałek „magii” w niektórych przypadkach poza to, co bezpośrednie wywołanie funkcji będzie. Efekt ten jest określony jako (cytowanie N4296 [refwrap.invoke]):

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

zwrócone: INVOKE(get(), std::forward<ArgTypes>(args)...). (20.9.2)

gdzie get() zwraca odniesienie do tego, co opakowuje reference_wrapper. INVOKE opisano w 20.9.2 [func.require]

INVOKE(f, t1, t2, ..., tN) zdefiniować w następujący sposób:

(1,1) - (t1.*f)(t2, ..., tN) gdy f jest wskaźnik funkcji do klasy T i t1 jest obiekt typu T lub odniesienie do obiektu typu T lub odniesienie do obiektu typu pochodnego od T;

(1,2) - ((*t1).*f)(t2, ..., tN) gdy f jest wskaźnikiem do funkcji do klasy T i t1 nie jest jednym z typów opisanych w poprzednim akapicie;

(1,3) - t1.*f gdy N == 1 i f jest wskaźnikiem do danych należących do klasy T i t1 jest obiektem typu T lub odniesienie do obiektu typu T lub odniesienie do obiektu typu pochodzącego od T;

(1,4) - (*t1).*f gdy N == 1 i f jest wskaźnikiem do danych należących do klasy T i t1 nie jest jednym z typów opisanych w poprzednim akapicie;

(1,5) - we wszystkich pozostałych przypadkach.

Wynikiem wywoływania ref(f) zamiast po prostu f jest to, że wskaźnik do funkcji członków i wskaźnik do członków dane mogą być „o nazwie” z odpowiednim obiektem wskaźnik/odniesienia jako parametr. Na przykład,

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

nazwałbym foo na A, B i C tymczasowych obiektów i przedmiotów przechowywanych w unique_ptr (DEMO). Dlaczego ktoś miałby preferować do korzystania z ref(f) przez f będzie oczywiście zależało od kontekstu, w którym używa się for_each_arg.

+0

Interesująca, jeszcze jedna magiczna cecha 'std :: reference_wrapper'. Zastanawiasz się, dlaczego Eric Niebler uważa to za niepotrzebne. – inf

+0

@bamboon Trudno powiedzieć bez większego kontekstu.Spekulowałbym, że 'ref()' dodaje 5 kolejnych postaci, a ich wyeliminowanie skutkuje krótszym kodem do celów golfowych. – Casey

+0

Dlaczego 'auto f = std :: ref (& A :: foo);' fail, ale 'auto f = & A :: foo; auto f2 = std :: ref (f) 'udało? – Barry