为什么 lambda 函数默认删除推导的返回类型引用?

2024-03-04

在 C++14 中,为什么具有推导返回类型的 lambda 函数默认会删除返回类型中的引用? IIUC,因为具有推导返回类型(没有显式尾随返回类型)的 C++14 lambda 函数的返回类型为auto,它会删除引用(除其他外)。

为什么做出这个决定?在我看来,当返回语句返回的内容是删除引用时,这似乎是一个陷阱。

这种行为给我带来了以下令人讨厌的错误:

class Int {
public:
   Int(int i) : m_int{i} {}
   int m_int;
};

class C {
public:
    C(Int obj) : m_obj{obj} {}
    const auto& getObj() { return m_obj; }
    Int m_obj;
};

class D {
public:
    D(std::function<const Int&()> f) : m_f{f} {}
    std::function<const Int&()> m_f;
};

Int myint{5};
C c{myint};
D d{ [&c](){ return c.getObj(); } } // The deduced return type of the lambda is Int (with no reference)
const Int& myref = d.m_f(); // Instead of referencing myint, myref is a dangling reference; d.m_f() returned a copy of myint, which is subsequently destroyed.

初始化时指定所需的返回类型d解决问题:

D d{ [&c]() -> const Int& { return c.getObj(); } }

有趣的是,即使auto返回类型推导是有道理的,这不是一个错误吗std::function<const Int&>使用返回非引用的函数愉快地初始化?我也通过明确地写道:

D d{ [&c]() -> Int { return c.getObj(); } }

编译没有问题。 (在Xcode 8, clang 8.0.0)


我认为你绊倒的地方实际上是这个表达c.getObj()在行中return c.getObj();.

你认为表达c.getObj()有类型const Int&。然而事实并非如此;表达式从来没有引用类型。正如 Kerrek SB 在评论中指出的那样,我们有时会谈论表达式,就好像它们具有引用类型一样,作为节省冗长的捷径,但这会导致误解,所以我认为了解真正发生的事情很重要。

在声明中使用引用类型(包括作为返回类型,如getObj的声明)会影响被声明的事物的初始化方式,但是一旦初始化,就不再有任何证据表明它最初是一个引用。

这是一个更简单的例子:

int a; int &b = a;  // 1

versus

int b; int &a = b;  // 2

These two codes are exactly identical (except for the result of decltype(a) or decltype(b) which is a bit of a hack to the system). In both cases the expressions a and b both have type int and value category "lvalue" and denote the same object. It's not the case that a is the "real object" and b is some sort of disguised pointer to a. They are both on equal footing. It's one object with two names.

现在回到你的代码:表达式c.getObj()具有与完全相同的行为c.m_obj,除了访问权限。类型是Int值类别是“左值”。这&在返回类型中getObj()仅表明这是一个左值,并且它还将指定一个已经存在的对象(大约而言)。

所以推导出来的返回类型return c.getObj();是一样的return c.m_obj;,为了与模板类型推导兼容,如其他地方所述,它不是引用类型。

注意。如果你理解这篇文章,你也会明白为什么我不喜欢“引用”的教学法被教导为“自动解引用的伪装指针”,这是错误和危险之间的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 lambda 函数默认删除推导的返回类型引用? 的相关文章

随机推荐

  • 如何在 celery 内为每个用户生成队列?

    因此 我尝试将 Web 请求中的阻塞内容移至后台任务并利用队列 我对消息传递和发布 订阅也很陌生 用户将数据推送到那里并进行处理 稍后用户会收到相关通知 我为此做了一个 celery 设置 发现它不能满足我为每个用户分配自己的任务的专用队列
  • Android 和设置(图像)视图 alpha 的 alpha

    真的没有对应的 XML 属性吗 setAlpha int 如果没有 还有哪些替代方案 它比其他响应更容易 有一个xml值alpha需要双值 android alpha 0 0 那是看不见的 android alpha 0 5 透视 andr
  • Rails 5.2 中单独的secret_key_base?

    我刚刚从 5 1 升级到 5 2 我对这种 更好 的存储秘密的方法感到很困惑 也许我不明白 但现在开发和生产似乎已经 合并 成一个单一的SECRET KEY BASE也master key 它是否正确 如果没有 我如何使用单独的主密钥和SE
  • 使用 Firebase-PHP 验证 Firebase ID 令牌

    我正在使用 Firebase Auth 在以 PHP 编码的网络应用程序上授权用户 授权本身是用 Javascript 进行的 它在 Ajax 请求上执行以验证用户是否已登录 要在我已经实现的服务器上使用 Firebase AdminFir
  • 当我单击屏幕上的其他位置时,按钮的底部边框消失

    fiddle https jsfiddle net bbvxnsyo 这是我的 HTML 代码
  • 基于偏好的分组算法

    我正在寻找一种方法来根据偏好将人们分类 例如 假设有 100 名学生 每人将被分配到以下五个班级之一 科学 40 个座位 数学 15 个席位 历史 15 个席位 电脑 20 个座位 写作 10 个座位 每个学生都有三个按偏好排序的首选课程
  • 为 std::shared_ptr 分配内存的正确方法

    我已经实现了一个功能 其中身份被赋予给我并且不受我的控制 它返回std shared ptr
  • 使用 GraphQL 机制,但返回 CSV

    普通的 REST API 可能会让您以不同的格式请求相同的数据 并使用不同的Accept标头 例如application json or text html or a text csv格式化的响应 但是 如果您使用 GraphQL 则 JS
  • OpenGL ES 1.1:如何在不损失亮度的情况下更改纹理颜色?

    我希望能够在代码中更改粒子的颜色 因此可以使用任何颜色 所以我只有一种基本上具有亮度的纹理 我一直在使用glColor4f 1f 0f 0f 1f 应用颜色 我尝试过的每个 Blendfunc 都接近工作 最终都像下面的最后一张图片一样 我
  • 向下滚动到div+一定的边距

    我正在使用此脚本滚动到页面上的某个 div button click function html body animate scrollTop scrolltothis offset top 500 工作完美 这会将页面滚动到 scroll
  • Unix C 套接字服务器不接受连接

    事情是这样的 我正在用 C 语言 使用 unix 系统调用 编写一个简单的 tcp 套接字服务器 但我无法接受连接 据我所知 我很好地完成了服务器初始化 但是当我尝试连接到我打印出来的端口 参见下面的代码 时 它拒绝了 就好像什么都没有一样
  • CKEDITOR:如何转换所有 html 实体

    这是清单 http www elizabethcastro com html extras entities html http www elizabethcastro com html extras entities html我要么想启用
  • 运行混淆代码时是否会影响性能? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 All 我建议在我的组织的标准构建过程中添加代码混淆 人们提出的问题之一是 与运行未混淆的代码相比 运行混淆的代码是否会对性能产生影响
  • C#:使用 Winforms 关闭 SerialPort 的正确方法

    我有一个应用程序 我可以从串行端口读取数据 一切正常 直到我关闭该应用程序 当我单击 X 时 应用程序只是挂起 UI 无响应 我从 DataReceived 事件处理程序中的端口读取数据 并在 FormClosed 发生时关闭端口 priv
  • 我是否应该始终在 ASP.NET Core API 控制器中使用 async/await [重复]

    这个问题在这里已经有答案了 作为一个例子 我有一个ASP NET Core API controller从服务中获取一些数据并2实现控制器方法的可能方法 使用异步 等待 HttpGet public async Task
  • Android 布局与 sw600dp 和 sw720dp

    我想支持600dp我的 Android 应用程序中的屏幕 所以我使用了该布局layout sw600dp 但我无法通过应用程序获得确切的布局 I got 800 X 1280屏幕尺寸与layout sw720dp但布局有点差720 X 12
  • 将视图控制器分配给prepareForSegue中的变量时,Swift EXC_BREAKPOINT

    当尝试使用我的destinationViewController 执行变量赋值时 我收到错误 错误信息是这样的 线程 1 EXC BREAKPOINT 代码 EXC I386 BPT 子代码 0x0 这在我的prepareForSegue函
  • 推荐?对于我们特定的 HTML -> PDF 项目

    我有一个问题 我从谷歌搜索中看到这个问题已经被详细讨论过 但我想知道你会根据我们的特殊需求推荐什么 我希望在一周的工作后发现我选择了错误的工具之前走在正确的轨道上 一个可以工作的工具 但其特殊性最终会在我们的项目中排除它 我已经在 Stac
  • 按名称(而不是 ID)直接链接到 App Store 中的评论页面

    我想知道如何直接链接到我的 iOS 应用程序的评论页面 而不知道应用程序 ID 只知道名称 我知道可以通过使用链接到没有应用程序 ID 的应用程序 itms apps itunes com apps APPNAME 您可以链接到评论页面 但
  • 为什么 lambda 函数默认删除推导的返回类型引用?

    在 C 14 中 为什么具有推导返回类型的 lambda 函数默认会删除返回类型中的引用 IIUC 因为具有推导返回类型 没有显式尾随返回类型 的 C 14 lambda 函数的返回类型为auto 它会删除引用 除其他外 为什么做出这个决定