转发引用作为函子参数的优点

Advantages of forwarding references as functor arguments

本文关键字:参数 引用 转发      更新时间:2023-10-16

有很多关于新的c++转发引用的讨论。然而,有时在特定的情况下,我仍然不清楚它们是否提供了任何优势。

很明显,按值传递重状态函子(就像随机数生成器一样)不是一个好主意。我们用参考文献。好的,但是…

…使用转发像

这样的引用有什么好处吗?
template <class T, class Functor>
T func(T x, Functor &&f)
{
    T y;
    // do some computations involving f(x) and store it in y
    return y;
}

代替const引用

template <class T, class Functor>
T func(T x, const Functor &f)
{
    T y;
    // do some computations involving f(x) and store it in y
    return y;
}

在函数中接受函数对象而不转发它们?

问题的主要方面是对性能的考虑。

选择取决于f做什么,接受右值是否有意义,是否期望函数对象很小,以及引用语义是否有意义。大多数标准库算法都是按值获取函数对象,因为期望它们很少或没有状态,而按值获取可能更有效。

获取转发引用的一个很好的例子是std::shuffle:

template< class RandomIt, class URNG >
void shuffle( RandomIt first, RandomIt last, URNG&& g );

URNG必须被参考,因为1)它不需要被复制,2)你真的不想复制它(因为RNG复制起来非常昂贵,因为用户通常希望shuffle改变RNG的状态;如果对同一个RNG对象的shuffle的两次调用导致相同的"随机"顺序,他们会非常惊讶)。你也不能通过const引用来获取它,因为那样你就不能对它调用operator()——生成一个随机数会改变RNG的状态。

则在非const左值引用URNG&和转发引用URNG&&之间进行选择。由于有时您确实希望接受右值URNG—例如,当您希望洗牌到相同的可重复顺序时,因此您在调用点创建了一个具有固定种子的生成器—因此选择了后者。

转发引用版本可以绑定Functor s, operator()声明为const非const

下面是一个编译前向引用而不是const引用的例子:

template <class T, class Functor>
T func(T x, Functor &&f)
{
    T y;
    y = f(x);
    return y;
}
template <class T, class Functor>
T func2(T x, const Functor &f)
{
    T y;
    y = f(x);
    return y;
}
int main()
{
    int a = 1;
    auto add_a = [=](int x) mutable { return ++a; };
    func(0, add_a); // compile
    func2(0, add_a); // does not compile
}
http://coliru.stacked-crooked.com/a/3eeb21a57d66452b

因为你的mutable lambda没有operator const (int)

换句话说,调用一个可变lambda会改变它,但是你不能改变const引用。所以你需要使用前向引用