首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数参数包中的“&&”

函数参数包中的“&&”
EN

Stack Overflow用户
提问于 2018-01-18 17:38:16
回答 3查看 6.4K关注 0票数 10

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

代码语言:javascript
复制
template<typename... Args>
void Function(Args... args)
{
}

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

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

代码语言:javascript
复制
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());

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

有人能解释一下这两者之间的区别吗?请解释一下两者之间有什么优势?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-01-18 18:00:15

它们在参数包表单中转发引用。对于模板参数的推导,它们可以匹配任意参数,但模板参数的推导与普通模板参数不同。

转发引用的主要优点是,如果与std::forward一起使用,将保留lvalue/rvalue信息。因此,他们习惯于“转发”一些东西。

例如,

代码语言:javascript
复制
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)...); }

普通版本总是调用real_foo(A const &)版本,因为在foo_proxy中,args总是值。

但是,如果传入的参数确实是rvalue,则完美版本将选择real_foo(A&&)

将转发引用和参数包相结合,可以方便地编写泛型代理函数,而不损失lvalue/rvalue的性能。

票数 6
EN

Stack Overflow用户

发布于 2018-01-18 18:01:44

的上下文中使用T&&

代码语言:javascript
复制
template<typename T>
void f(T&& t);

称为转发引用,有时也称为通用引用

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

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

以下是一些比我能解释得更好、更详细的材料:

票数 4
EN

Stack Overflow用户

发布于 2018-01-18 18:00:36

有人能解释一下这两者之间的区别吗?请解释一下两者之间有什么优势?

参数包与单个参数的差别是相同的。Args声明了一个“对象参数”(按值传递),而Args&&声明了一个引用参数(通过引用传递)。

通过引用传递可以避免在没有必要时复制参数。如果引用是非const,则还允许修改所引用的参数,这包括从该对象移动的可能性。

传递的值使调用者清楚地知道,传递的对象既不会被修改,也不会因为调用函数而被引用。

我的第一个想法是& form将专门用于r-value对象。

正如您的测试所显示的,这确实是一个错误的假设。当Args是一个推导类型,即auto或模板参数时,Args&&确实可以是l值引用或r值引用。它是哪一个取决于推导出的Args是什么。这简要地说明了引用折叠规则:

代码语言:javascript
复制
typedef int&  lref;
typedef int&& rref;
int n;
lref&  r1 = n; // type of r1 is int&
lref&& r2 = n; // type of r2 is int&  note this case in particular
rref&  r3 = n; // type of r3 is int&
rref&& r4 = 1; // type of r4 is int&&

使用这种引用允许转发,即重新绑定到一个新的lvalue引用(在可能的情况下)或从对象中移动(在可能的情况下)或复制(当前两者都不可能时)。

正因为如此,当Args&&是推断类型时,Args被称为转发引用(或通用引用)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48327250

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档