【问题标题】:Must I use lambda to pass a member function as std::function?我必须使用 lambda 将成员函数作为 std::function 传递吗?
【发布时间】:2022-01-10 16:58:55
【问题描述】:

以下代码有效,但我觉得worker([this](int a, long b, int* c){receiver(a, b, c);}); 行有点多余,因为它重复了receiver 的签名。我可以通过某种方式直接传递成员函数,而不是传递一个依次调用成员函数的 lambda 函数吗?

using callback = std::function<void(int, long, int*)>;

void worker(callback c)
{
    c(1,2L,(int*)3);
}

class Caller
{
public:
    Caller()
    {
        worker([this](int a, long b, int* c){receiver(a, b, c);});
    }

    void receiver(int a, long b, int* c)
    {
    }
};

【问题讨论】:

标签: c++ std-function


【解决方案1】:

如果您可以访问 C++20,请使用 bolov 的答案。 如果没有……

虽然这仍然使用 lambda,但您可以利用参数包来避免重复签名:

worker([this](auto... params) { receiver(params...); });

这需要 C++14 或更高版本。

如果您有更复杂的类型并希望避免复制,可以添加完美转发:

worker([this](auto&&... params) {
    receiver(std::forward<decltype(params)>(params)...);
});

【讨论】:

    【解决方案2】:

    std::bind 是经典的方法,它避免了明确拼写转发签名的需要:

    using namespace std::placeholders;
    
    // ...
    
        worker(std::bind(&Caller::receiver, this, _1, _2, _3));
    

    C++20 也有std::bind_front;它在一定程度上减少了这种措辞。

    您不能“直接”传递指向成员函数的指针。这是因为成员函数需要一个对象的特定实例,该对象的成员函数应该被调用。因此,以某种方式,以某种方式,您无法避免 this 或对象的其他实例参与该过程。这是 C++ 的基础。这里唯一能做的就是找到一些语法糖,基本上就是这里了。

    【讨论】:

    • 虽然std::bind 被认为是过时的并且clang-tidy 会用警告标记这个代码。此外,占位符:1)对读者隐藏参数的类型 2)对编译器隐藏参数的类型,因此需要“手动”解析,这看起来比转发更丑
    【解决方案3】:

    最干净的方式是C++20的std::bind_front

    worker(std::bind_front(&Caller::receiver, this));
    

    Why use `std::bind_front` over lambdas in C++20?

    【讨论】:

    • 这似乎是最干净的解决方案,它在 VC++ 2022 中工作,但不幸的是我使用的编译器(ESP8266 SDK)似乎只支持 C++17,它似乎不支持有bind_front,但只有bind。这么近……
    • @DamnVegetables 是的,C++20 是相当新的。请牢记此解决方案以备将来使用:p
    猜你喜欢
    • 2017-01-18
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2017-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多