如果C++ 11的lambda表达式支持默认参数怎么办?

xml*_*lmx 28 c++ lambda default-arguments c++11

我认为以下代码非常方便且无害:

auto fn = [](bool b = false) -> int // NOT legal in C++11
{
    return b ? 1 : 0;
}; 
Run Code Online (Sandbox Code Playgroud)

为什么C++ 11明确禁止lambda表达式的默认参数?

我只是想知道背后的理由和考虑因素.

我想知道"为什么"而不是C++ 11标准所说的"什么".

Die*_*Epp 19

lambda不能有默认参数.但是,使用lambdas有两种主要方法,其中只有一种方法允许默认参数而不更改类型系统.

  1. 您可以直接调用lambda,也可以通过模板调用lambda.在这种情况下,默认参数可以正常工作.

  2. 你可以通过调用lambda std::function.如果不更改类型系统,默认参数将无法工作.

我的猜测是,人们在编写新的功能C++ 11将通常采取std::function的参数,因为这样一来,该功能不会成为一个模板,否则不会有实例化每一个Lambda和仿函数来说,得到传递给它.

为什么a std::function(或函数指针)不能采用默认值?

这种功能的类型并不明显.

  • 如果是std::function<int(bool)>,那么你如何用默认值来调用它?(你不能.)

  • 如果是std::function<int(bool=false)>,那么它与哪些类型兼容,以及转换如何工作?你能把它转换成std::function<int()>?怎么样std::function<int(bool=true)>

  • 如果它是新的std::function<int(bool=default)>,那么它兼容什么类型,转换如何工作?

基本上,这不仅仅是一个开关,你可以在标准中翻转并使函数指针/ std::function处理默认参数.普通函数中的默认参数是使用函数声明中的信息处理的,该函数在调用站点上不可用于lambda或函数指针.因此,您必须将有关默认值的信息编码到函数类型中,然后计算出所有非显而易见的转换和兼容性规则.

因此,您必须提出一个令人信服的案例,说明为什么要添加这样的功能,并说服委员会.

那么,为什么lambdas不能采取默认值?

我没有回答这个问题.但我认为这不是一个非常有用的功能.如果可以的话,我会删除这个答案,但它已经被接受了.如果可以的话,我会贬低它,但这是我的.这就是生活.

  • @SethCarnegie:因为lambda函数没有函数声明,所以它们只有类型.这也适用于通过指针调用的任何函数. (2认同)
  • 我很抱歉,但这根本没有意义.如果你想知道为什么它没有意义并希望我撤消我的downvote,你可以提出一个新的SO问题(似乎我的评论中的解释不够详细).几个ppl已经指出lambda是"只是"一个类型的函数对象,可以有默认参数. (2认同)

Lig*_*ica 5

我同意在某些情况下允许 lambdas 中的默认参数工作本身没有真正的“技术”限制。它不会破坏您的指针 and ,因为函数的类型不受默认参数的影响。但这也是为什么这不是非常实用的原因。auto

为什么?

因为默认参数虽然是函数签名的一部分,但不是函数类型的一部分:

[C++11: 1.3.17]:
签名
<function> 名称、参数类型列表 (8.3.5) 和封闭的命名空间(如果有)
[注意:签名用作名称修改和链接的基础。——尾注]

[C++11: 8.3.5/6]: [..]返回类型、参数类型列表引用限定符cv-qualifier-seq,但不是默认参数 (8.3.6) 或异常规范 (15.4),是函数类型。[注意:在函数指针、函数引用和成员函数指针的赋值和初始化过程中检查函数类型。——尾注]

它们本质上是一块语法糖,由编译器“激活”,能够看到您使用的函数的声明,并在函数调用点注入:

#include <iostream>

void foo(int x = 5)
{
   std::cout << x << '\n';
}

int main()
{
   foo();
}
Run Code Online (Sandbox Code Playgroud)
  • 输出: 5

默认参数是“可见”。

但是,当您将函数“隐藏”在指针后面时:

int main()
{
    void (*bar)(int) = &foo;
    bar();
}
Run Code Online (Sandbox Code Playgroud)
  • 错误: too few arguments to function

该类型bar是正确的,编译器知道foo有一个默认的,但根本就没有有直接存在于调用点通知编译器的语法barbarfoo。当然,在这个微不足道的场景中,它可以通过观察赋值来解决这个问题,但这对于更广泛的论点来说几乎没有理由。

出于同样的原因,仅在调用站点不可见的定义中声明的默认参数几乎无用:

// a.h
void foo(int);

// a.cpp
#include "a.h"
#include <iostream>

void foo(int x = 5)
{
   std::cout << x << '\n';
}

// main.cpp
#include "a.h"

int main()
{
    foo();
}
Run Code Online (Sandbox Code Playgroud)
  • main.cpp 中的错误: too few arguments to function

我想这就是原因:

[C++11: 8.3.6/4]: [..]不同作用域中的声明具有完全不同的默认参数集。[..]

我们允许“堆积”类非模板成员函数定义默认参数([C++11 8.3.6/6]); 该示例表明此默认值仍仅适用于同一个 TU,这遵循我们在上面的第二个代码片段中看到的行为。

因此,如果默认参数不是函数类型的一部分,并且必须对调用站点明确可见,那么只有少数人为的极端情况对 lambda 有用,也就是在调用它们时在创建它们的同一范围内,以便编译器可以轻松地找出如何“填充” lambda 调用的默认参数,那么,这有什么意义呢?不是很多,我告诉你。