将捕获“this”的 lambda 传递给成员初始值设定项列表中的 obj

Pass lambda that captures "this" to obj in member initializer list

提问人:glades 提问时间:10/13/2022 更新时间:10/13/2022 访问量:59

问:

我有以下问题:我定义了一个位于另一个类对象中的类。我想在该类中保存一个闭包,以便以后调用它。现在,我应该如何精确地初始化容器类中的对象?我不能在“顶级”使用(例如,当我在直接成员初始化中使用它时。另一方面,当我 decltype() 一个空的 lambda 时,它给了我错误的类型,因为它似乎没有关闭。查看以下代码:tasktasktaskthisthis

演示

#include <cstdio>

template <typename Callable>
struct task
{
    task(Callable fn)
    :   fn_{fn}
    { }

    auto do_stuff() {
        fn_();
    }

    Callable fn_;
};

struct container
{
    container()
        :  task_([this]() -> void { this->print(); })
    { }

    auto print() -> void {
        printf("Hello World!\n");
    }

    auto execute() {
        task_.do_stuff();
    }

    task<decltype([](){})> task_;
};

int main()
{
    container a;

    a.execute();
}

具体而言,这会产生:

<source>:20:12: error: no matching function for call to 'task<container::<lambda()> >::task(container::container()::<lambda()>)'
   20 |         :  task_([this]() -> void { this->print(); })
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

如何在直接成员初始化或成员初始值设定项列表中创建闭包?this

C++ Lambda 闭包成员 初始化

评论


答:

2赞 lorro 10/13/2022 #1

如果您希望能够为此分配不同的功能,则需要类型擦除:。此外,您需要在代码中包含 before ctor。task_std::function<void()> task_;print()

如果你只需要一个功能,那么基本上是一个成员函数。task_

如果这些都不适合你,你仍然可以在层次结构中引入一个间接层,:containerBase

struct containerBase
{
    void print() {
        printf("Hello World!\n");
    }

    auto g() { return [this]() -> void { this->print(); }; }
};

struct container : containerBase
{
    container()
        :  task_(g())
    { }

public:
    auto execute() {
        task_.do_stuff();
    }

    task<decltype(std::declval<containerBase>().g())> task_;
};

评论

0赞 glades 10/13/2022
有趣的解决方案,但是第二个示例中的此指针将属于 containerBase 类型。因此,我需要虚拟调用才能访问容器成员函数,这并不理想。难道就没有更直接的解决方案了吗?
0赞 lorro 10/13/2022
@glades 这个想法是,你几乎把所有东西都放在;只有 CTOR(分配 ),调用函数和本身都在 中。containerBasetask_task_task_container
0赞 glades 10/13/2022
我明白这一点,但这实质上意味着每个包含任务对象的容器都会扩展其层次结构以满足其需求。这并不理想。我在想,也许std::bind毕竟不是一个糟糕的解决方案。