【问题标题】:Creating std::function with a member function does not compile使用成员函数创建 std::function 无法编译
【发布时间】:2019-11-07 14:15:12
【问题描述】:

我正面临 C++ 类的编译问题。

我的代码在这里:

#include <chrono>
#include <cstdint>
#include <thread>
#include <functional>

class Monitors {

public:

    Monitors(std::uint32_t timeout1, std::uint32_t timeout2) : timeout_1(timeout1), timeout_2(timeout2) {
        timer_start(task_1, timeout1); //does not compile
        timer_start(&Monitors::task_2, timeout2); //does not compile either

    }

private:

    void timer_start( std::function<void(void)>& func, std::uint32_t interval) {
        std::thread([func, interval]() {
            while (true) {
                func();
                std::this_thread::sleep_for(std::chrono::milliseconds(interval));                }
        }).detach();
    }

    void task_1() {
    }

    void task_2() {
    }


private:

    std::uint32_t timeout_1;
    std::uint32_t timeout_2;
};

错误是:

非 const 左值类型 std::function 不能绑定到临时 输入无效

有什么问题?我该如何解决?

【问题讨论】:

  • 请小心那个sleep_until 电话。想想如果func 的执行时间长于interval 会发生什么。改变你做事的顺序将解决这个问题。
  • 是的,我修改了代码。

标签: c++ c++14 std-function


【解决方案1】:

编译器需要将成员函数转换为std::function&lt;void()&gt;对象以匹配timer_start函数参数列表。

这个对象是一个临时对象,一旦调用timer_start,它的生命周期就会结束。并且临时对象不能绑定到非常量引用(这就是错误消息的意思)。

简单的解决方案是按值传递函数

void timer_start( std::function<void(void)> func, uint32_t interval)

第二个问题是,对于成员函数,您总是需要使用地址操作符来获取指向它的指针。而且你总是需要指定类。

这意味着你需要做的事情

timer_start(&Monitors::task_1, timeout1);
timer_start(&Monitors::task_2, timeout2);

最后是第三个问题:非静态成员函数是特殊的,因为它们需要调用一个对象。这个对象就是函数内部的this指针。

调用函数的对象通常作为隐藏的第一个参数传递,但在使用例如std::function 我们需要明确指定该参数。

所以最终的声明需要是

void timer_start( std::function<void(Monitors*)> func, uint32_t interval)

这最后一件事也意味着你需要将一个指向对象的指针传递给函数,在你的情况下你可以传递this

// Capture this
//           vvvv
std::thread([this, func, interval]() {
    while (true) {
        auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
        func(this);
        //   ^^^^
        // Pass this as argument
        std::this_thread::sleep_until(x);
    }
}).detach();

【讨论】:

  • 不,仍然无法编译。 &Monitors::task_N 或 task_N
  • @CaptainNemo 更新了我的答案
猜你喜欢
  • 1970-01-01
  • 2015-10-03
  • 2015-11-24
  • 2023-03-31
  • 1970-01-01
  • 2015-03-04
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多