C++ 中的可调用类对象:没有用于调用‘std::tuple<T>::tuple(<brace-enclosed initializer list>)’的匹配函数

问题描述

我的代码由 2 个文件组成:main.cpputils.hpp。这些文件内容如下:

utils.hpp

#ifndef UTILITY_HPP
#define UTILITY_HPP

#include <iostream>
#include <thread>
#include <future>
#include <functional>
#include <chrono>

using std::chrono::milliseconds;

class CallableStoppableTask {
    std::promise<void>  exit_signal;
    std::future<void>   future_obj;

    public:

    CallableStoppableTask() : future_obj(exit_signal.get_future()) {}

    CallableStoppableTask(const CallableStoppableTask&) = delete;
    CallableStoppableTask& operator=(const CallableStoppableTask&) = delete;

    virtual void run() = 0;

    void operator()() { run(); }

    bool is_stop_requested(int timeout_milliseconds = 0) const {
        return (future_obj.wait_for(milliseconds(timeout_milliseconds)) == std::future_status::ready);
    }

    void request_stop() { exit_signal.set_value(); }
};


struct Car {
    int     model;
    int     price;

    explicit Car(const int& arg_model = -1,const int& arg_price = -1)
    : model(arg_model),price(arg_price) {}
};

class CallableSampleTask : public CallableStoppableTask {
    
    CallableSampleTask(const CallableSampleTask&) = delete;

    CallableSampleTask& operator=(const CallableSampleTask&) = delete;

    void run() override {
        std::cout << "Running Some Car Sample Task.. " << std::endl;
    }

public:
    CallableSampleTask(const Car& arg_car = Car()) {}
};

#endif

为了实现一个可以被中断的任务,我们继承了 CallableStoppableTask 例如,CallableSampleTask

main.cpp内容是:

#include "utils.hpp"
#include <iostream>
#include <array>
#include <future>
#include <memory>

#define NUM_TASK 5

static std::array<std::unique_ptr<CallableSampleTask>,NUM_TASK> ar_uptr_task;

int main() {
    std::unique_ptr<CallableSampleTask> f = std::move(std::make_unique<CallableSampleTask>());
    (*f.get())();   // COMPILE TIME ERROR: what is the error in this?

    ar_uptr_task.fill(std::move(std::make_unique<CallableSampleTask>()));

    for (int i = 0; i < NUM_TASK; i++) {
        // I want to do something like this. COMPILE TIME ERROR
        auto discard_ret = std::async(std::launch::async,(*ar_uptr_task[i].get()));
    }

    std::cout << "Hello,World!" << std::endl;
    return 0;
}

上面抛出了一个非常大的编译时间错误。我已经注释了 main.cpp 文件中引发错误的行。

我正在使用以下命令进行编译:

g++ -std=c++17 -pthread main.cpp

知道我哪里出错了吗?

PS:如果我遗漏了什么,请用伟大的 C++ 概念启发我。

我无法发布错误,因为它超出了 stackoverflow 限制。这是 github 链接https://github.com/KishoreKaushal/CallableObjects

解决方法

这条线没问题

(*f.get())();   // COMPILE TIME ERROR: what is the error in this?

但较短的版本

(*f)();

更好。


ar_uptr_task.fill(std::move(std::make_unique<CallableSampleTask>()));

没有任何意义。 fill 将源作为常量对象,你想如何对 const 源对象应用移动操作[你也想移动源对象 N 次,但第一次移动操作将源对象留空状态]?

可以替换为:

for (int i = 0; i < 5; ++i)    
    ar_uptr_task[i] = std::make_unique<CallableSampleTask>();

如果要将函子传递给 async 函数,请使用 reference_wrapper 将其包装在 ref 中:

 for (int i = 0; i < NUM_TASK; i++) {
     auto discard_ret = std::async(std::launch::async,std::ref(*ar_uptr_task[i]));
 }

Demo