RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1000473
Accepted
AccumPlus
AccumPlus
Asked:2020-07-08 16:31:04 +0000 UTC2020-07-08 16:31:04 +0000 UTC 2020-07-08 16:31:04 +0000 UTC

使用默认参数的 Lambda 表达式类型推断

  • 772

在不使用 option-Wpedantic的情况下,启用 c++11 的编译器允许在 lambda 表达式中使用默认值。

对于这样的表达式,您可以使用std::function指定所有参数类型的类型,包括默认指定的参数。

但是,当使用带有 auto 关键字的自动类型推断时,lambda 表达式采用特定类型,例如main()::<lambda(int)>,其中括号中的值是传递给表达式的参数的类型。并且这些值总是被指定,不管它们是否有默认值(这通常是合乎逻辑的)。

下面是一个代码示例。

#include <functional>
#include <iostream>

void f1(std::function<int()> lambda)
{
    if (lambda)
    {
        std::cout << lambda() << std::endl;
    }
}

void f2(std::function<int(int)> lambda)
{
    if (lambda)
    {
        std::cout << lambda(1) << std::endl;
    }
}

int main()
{
    auto lambda1 = [](int a = 3) -> int
    {
        return a;
    };

    f1(lambda1);
    f2(lambda1);

    std::function<int()> lambda2 = []()
    {
        return 1;
    };

    std::function<int(int)> lambda3 = [](int a)
    {
        return a;
    };

    f1(lambda2);
    //f2(lambda2); // Очевидно несоответствие типов

    //f1(lambda3); // Очевидно несоответствие типов
    f2(lambda3);
}

在代码示例中,类型main()::<lambda(int)>被强制转换为std::function<int()>. 我没有足够的知识来理解为什么编译器不会对类型不匹配发誓。请帮我解释一下。

以及相关问题。

我可以明确指定一种类型,比如自动推断的类型吗?

我可以告诉编译器不允许这种类型的转换吗?

c++
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    AnT stands with Russia
    2020-07-09T00:00:49Z2020-07-09T00:00:49Z

    由 lambda 表达式生成的闭包对象的类型独立于 lambda 参数,并且不由 lambda 参数决定。默认参数的存在或不存在在这里没有任何作用。每个 lambda 表达式都会产生一个新的唯一类型——这就是你需要知道的关于闭包对象的类型。即使两个 lambda 表达式完全相同,它们仍然会以任何方式彼此不相关的唯一类型结束。在您的示例中,您在此类型的内部名称中看到了参数列表的一些提示,这只不过是您使用的实现的一个装饰性功能。但是,您在编译器消息中看到的闭包对象类型的文本描述并不是对实际类型的详尽描述。

    例如,响应

    auto f1 = [](){};
    auto f2 = [](){};
    &f1 == &f2;
    

    您将收到来自 GCC 的诊断消息,例如

    error: comparison between distinct pointer types 
      'main()::<lambda()>*' and 'main()::<lambda()>*' lacks a cast
    

    如您所见,引号中的类型描述完全相同。但是,它们是不同的、不相关的类型。

    因此,在使用 lambda 表达式时,根本谈不上“类型匹配”:所有类型的闭包对象都是唯一的,并且从不对应任何东西。

    为什么编译器不抱怨类型不匹配

    该类std::function<>建立在类型擦除的原则之上,即 事实上,它是一个更加专业化的类比std::any。此类的构造函数是模板化的(参见此处的第 5 点)——它没有也不能在语言的底层类型系统级别进行任何“类型匹配”检查。在语言的基本类型系统级别,这个构造函数可以接受任何类型作为输入。

    通过 SFINAE 等技术,任何检查都已经在库实现的级别上挂在此构造函数上。初始化视图时,会检查Callablestd::function<F> sf = f;要求:对象必须是Callable类型的函数。检查此要求,它适用于您的示例。fF

    例如,闭包对象lambda1是Callable和 asint()和 as int(int)。因此,您可以将它用于初始化std::function<int()>和初始化std::function<int(int)>。

    我可以明确指定一种类型,比如自动推断的类型吗?

    明显不是。闭包对象的类型是实现定义的,没有明确指定它的语法。您只能在它已经显示后隐式地“指定”它 - 通过decltype对已经存在的对象应用闭包

    auto f1 = [](){};
    decltype(f1) f2 = f1;
    

    我可以告诉编译器不允许这种类型的转换吗?

    编译器与它无关。您正在处理纯库功能:std::function<>. 只要您使用 class std::function<>,它就会按照语言规范的要求运行。

    • 8
  2. user7860670
    2020-07-08T16:45:51Z2020-07-08T16:45:51Z

    禁止在 lambda 表达式中指定默认参数被认为是一个缺陷,并在标准的后续版本中被取消。因此,编译器对此类操作持保留态度。lambda 表达式的类型是匿名的,因此将显式引用它,或者您不能以任何其他方式显式指定它。它std::function有一个隐式模板构造函数,可以接受适当的 lambda 表达式对象,因此您无能为力。

    • 4
  3. AR Hovsepyan
    2020-07-08T17:22:53Z2020-07-08T17:22:53Z
    1. 编译器不发誓,因为 lambda_function 可以存储在对象中 std::function
    2. 你不能显式地指定一个类型_这个类型是依赖于实现的,只有编译器知道它的名字。
    3. 不执行类型转换(参见第 1 点),因此您不能指定不执行未执行的操作
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5