为什么我们不能在作为方法默认参数的 lambda 中捕获它?

Why can't we capture this in a lambda that is the default parameter of a method?

提问人:Victor 提问时间:9/8/2023 最后编辑:Mark RotteveelVictor 更新时间:9/14/2023 访问量:143

问:

我正在尝试捕获用作方法默认参数的 lambda 函数中的指针。this

我的目标是从 lambda 中调用此类的方法,这需要捕获指针。this

但是,以下代码会导致错误:

错误 C3639:作为默认参数一部分的 lambda 只能具有 init-capture

克服此限制的常见解决方案是什么?

#include <functional>

class A{
    public:
    void B(std::function<void()> a = [this](){}); //error C3639: a lambda that is part of a default argument can only have an init-capture.
};
C++ lambda 默认参数

评论

0赞 Marek R 9/8/2023
这是过时的 godbolt.org/z/q57dvPeG5this
3赞 StoryTeller - Unslander Monica 9/8/2023
如果内存可用,则在调用方端计算参数(甚至是默认参数)。那么在这种情况下是什么呢?this

答:

7赞 Caleth 9/8/2023 #1

您可以改为重载该函数

class A{
    public:
    void B(std::function<void()> a);
    void B(){ B([this](){}); };
};

评论

1赞 463035818_is_not_an_ai 9/8/2023
请注意,这个问题实际上是两个相关但略有不同的问题,“为什么不呢?(标题)和“用什么代替?这完美地回答了后者,但不是第一个。
1赞 Afshin 9/8/2023 #2

嗯,我认为你不能用捕获列表作为默认参数传递lamda是有道理的。它创建了不应该存在的依赖项。

但是你也许可以通过这样的事情来实现你想做的事情:

#include <functional>

class A{
    public:
    void B(std::function<void()> a) {
        if (!a) {
            // do default. You have access to 'this' here.
            return;
        }
        // do non-default with 'a' argument
    }
};

评论

0赞 Marek R 9/8/2023
在代码中添加不必要的分支对性能不利。
10赞 Jan Schultke 9/8/2023 #3

线路的问题......

void B(std::function<void()> a = [this](){});

...lambda 表达式是函数参数的默认参数。 函数参数是在调用站点创建的,此时无法捕获任何参数。 C++ 标准禁止默认参数:thisthis

[ 注意:该关键字可能不会出现在成员函数的默认参数中;请参阅 [expr.prim.this]。 [ 示例this

class A {
  void f(A* p = this) { }           // error
};

— 结束示例 ] — 结束语 ]

- [dcl.fct.default] 第 8 页

这只是一个注释,但对于 lambda 也是如此,因为:

默认参数中出现的 lambda 表达式不得隐式或显式捕获任何实体。

- [expr.prim.lambda.capture] 第 9 页

为什么不能在默认参数中使用的理由this

函数调用的处理方式如下:

  1. 初始化所有函数参数(可能使用默认参数)
  2. 将控制权移交给功能(现在可用)this
  3. 执行函数体并创建返回对象
  4. 将控制权转回呼叫者(不再可用)this
  5. 销毁函数参数

注意:步骤4的顺序。和 5.是实现定义的

您尝试在步骤 1 中访问,这还为时过早,更不用说默认参数中的 lambda 通常不能有捕获。this

溶液

添加第二个重载,例如

void B() { B( [this] {} ); }

可以解决问题,但您最终会得到两个函数而不是一个。