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;
}
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.
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.
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.
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 .
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)
whenf
is a pointer to a member function of a classT
andt1
is an object of typeT
or a reference to an object of typeT
or a reference to an object of a type derived fromT
;(1.2) —
((*t1).*f)(t2, ..., tN)
whenf
is a pointer to a member function of a classT
andt1
is not one of the types described in the previous item;(1.3) —
t1.*f
whenN == 1
andf
is a pointer to member data of a classT
andt1
is an object of typeT
or a reference to an object of typeT
or a reference to an object of a type derived fromT
;(1.4) —
(*t1).*f
whenN == 1
andf
is a pointer to member data of a classT
andt1
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With