Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

c++14

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;
}
like image 305
Martin Avatar asked Jan 26 '15 21:01

Martin


People also ask

What is the purpose of std :: ref?

std::ref. Constructs an object of the appropriate reference_wrapper type to hold a reference to elem . If the argument is itself a reference_wrapper (2), it creates a copy of x instead. The function calls the proper reference_wrapper constructor.

What does REF do in C++?

Inside the function, the reference is used to access the actual argument used in the call. This means that changes made to the parameter affect the passed argument. To pass the value by reference, argument reference is passed to the functions just like any other value.

Is std :: function copyable?

Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

What is the use of reference_wrapper?

A reference_wrapper<Ty> is a copy constructible and copy assignable wrapper around a reference to an object or a function of type Ty , and holds a pointer that points to an object of that type. A reference_wrapper can be used to store references in standard containers, and to pass objects by reference to std::bind .


1 Answers

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.

like image 137
Casey Avatar answered Oct 08 '22 12:10

Casey