函数参数包中的'&&'

Wad*_*Wad 8 c++

我已经看到多个代码实例,其中使用 && 表示法声明了函数参数包,如下所示,但我看不出使用这种表示法有什么好处。

template<typename... Args>
void Function(Args... args)
{
}

template<typename... Args>
void Function(Args&&... args)
{
}
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是 && 形式将专门用于 r 值对象,但这个测试证明是错误的:

struct Object
{
    // Added bodies so I see what is being called via a step-into
    Object() {}
    Object(const Object&) {}
    Object(Object&&) noexcept {}
    Object& operator=(const Object&) { return *this; }
    Object& operator=(Object&&) noexcept { return *this; }
};

Object GetObject() { Object o; return o; }

Object obj;

Function(GetObject());  
Function(GetObject());
Run Code Online (Sandbox Code Playgroud)

在这里,VS 2017 抱怨该函数的两种形式都是调用的可行候选者。

有人能解释一下这两者之间的区别吗,一个可能比另一个有什么优势?

AMA*_*AMA 7

T&&当在上下文中使用时

template<typename T>
void f(T&& t);
Run Code Online (Sandbox Code Playgroud)

称为转发参考,有时也称为通用参考

转发引用的主要优点std::forward是,与其结合可以实现所谓的完美转发:函数模板将其参数按原样传递给另一个函数(左值作为左值,右值作为右值)。

现在可以创建将其他函数作为参数或返回它们的高阶函数,或高级函数包装器(例如,std::make_shared),并执行其他很酷的事情。

这里有一些材料比我能更好、更详细地解释它:


lll*_*lll 6

它们以参数包形式转发引用。至于模板参数推导,它们可以匹配任何参数,但与普通模板参数相比,模板参数的推导方式会有所不同。

转发引用的主要优点是,如果与std::forward. 因此,它们被用来“转发”某些东西。

例如,

void real_foo(A const &a);
void real_foo(A &&a);

template<class... Args>
void foo_proxy_ordinary(Args... args) { real_foo(args...); }

template<class... Args>
void foo_proxy_perfect(Args&&... args) { real_foo(std::forward<Args>(args)...); }
Run Code Online (Sandbox Code Playgroud)

普通版本总是会调用real_foo(A const &)version,因为在里面foo_proxyargs总是左值。

但是,完美版本将选择real_foo(A&&)传入的参数是否确实是右值。

将转发引用与参数包相结合,可以轻松编写通用代理函数,而不会损失左值/右值方面的性能。