2015-01-26 35 views
10

为什么要喜欢调用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; 
} 
+2

这是不必要的。 https://twitter.com/ericniebler/status/559798611991879684 – inf 2015-01-26 21:22:44

回答

17

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是一个指针,指向类的成员函数Tt1T类型的对象或对T类型的对象的引用或对从T派生的类型的对象的引用;

(1.2) - ((*t1).*f)(t2, ..., tN)f时是一个指向类Tt1不是在前面的项中描述的类型中的一种的一个成员函数;

(1.3) - t1.*fN == 1f是一个指针,指向类的成员数据Tt1T类型的对象或T类型的对象或派生来的类型的对象的基准的基准来自T;

(1.4) - (*t1).*fN == 1f是一个指向类Tt1不是在前面的项中描述的类型之一的构件数据;

(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>()); 

将调用fooABC临时对象并在unique_ptrDEMO)保持的物体。为什么宁愿使用ref(f)而不是f显然将取决于使用的上下文for_each_arg

+0

有趣的,'std :: reference_wrapper'的又一个神奇功能。想知道为什么Eric Niebler认为这是不必要的。 – inf 2015-01-26 21:33:41

+0

@bamboon很难说没有更多的上下文。我会推测'ref()'增加了5个字符,并且为了代码高尔夫的目的而消除了它。 – Casey 2015-01-26 21:48:33

+0

为什么'auto f = std :: ref(&A :: foo);'失败,但是'auto f =&A :: foo; auto f2 = std :: ref(f)'成功了吗? – Barry 2015-01-26 22:02:06