Что такое std:: ref для этой функции?

Почему нужно сначала называть std:: ref вместо того, чтобы не называть его вообще?

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

Ответ 1

std::reference_wrapper::operator() выполняет несколько "магии" в некоторых случаях помимо того, что вызовет прямая функция. Его эффекты указаны как (цитирование N4296 [refwrap.invoke]):

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

Возвращает: INVOKE(get(), std::forward<ArgTypes>(args)...). (20.9.2)

где get() возвращает ссылку на то, что обертывает reference_wrapper. INVOKE описывается в 20.9.2 [func.require]:

Определите INVOKE(f, t1, t2, ..., tN) следующим образом:

(1.1) - (t1.*f)(t2, ..., tN), когда f является указателем на функцию-член класса T, а t1 является объектом типа T или ссылкой на объект типа T или ссылку на объект типа, полученного из T;

(1.2) - ((*t1).*f)(t2, ..., tN), когда f является указателем на функцию-член класса T и t1 не является одним из типов, описанных в предыдущем пункте;

(1.3) - t1.*f, когда N == 1 и f является указателем на данные элемента класса T и t1 является объектом типа T или ссылкой на объект типа T или ссылка на объект типа, полученного из T;

(1.4) - (*t1).*f, когда N == 1 и f является указателем на данные элемента класса T и t1 не является одним из типов, описанных в предыдущем пункте;

(1.5) - f(t1, t2, ..., tN) во всех остальных случаях.

Результат вызова ref(f) вместо простого f заключается в том, что функция-указатель-член-член и данные-указатели на элемент могут быть "вызваны" с соответствующим указателем/ссылкой объекта в качестве параметра. Например,

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

будет вызывать foo в A, B и C временных объектах и ​​объекте, хранящемся в unique_ptr (DEMO). Почему один предпочитает использовать ref(f) над f, очевидно, будет зависеть от контекста, в котором используется for_each_arg.