Martin
Martin

Reputation: 9369

What is std::ref useful for in this function?

Why should one prefer to call std::ref instead of not calling it at all?

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;
}

Upvotes: 10

Views: 952

Answers (1)

Casey
Casey

Reputation: 42564

std::reference_wrapper::operator() performs a bit of "magic" in some cases beyond what a direct function call would. Its effects are specified as (quoting 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)

where get() returns a reference to what the reference_wrapper wraps. INVOKE is described in 20.9.2 [func.require]:

Define INVOKE(f, t1, t2, ..., tN) as follows:

(1.1) — (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

(1.2) — ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

(1.3) — t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

(1.4) — (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;

(1.5) — f(t1, t2, ..., tN) in all other cases.

The result of calling ref(f) instead of simply f is that pointer-to-member-function and pointer-to-member-data can be "called" with an appropriate object pointer/reference as parameter. For example,

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

would call foo on the A, B and C temporary objects and the object held in the unique_ptr (DEMO). Why one would prefer to use ref(f) over f would obviously depend on the context in which one is using for_each_arg.

Upvotes: 17

Related Questions