c++ 如何将参数包和函数指针移动到结构中?

ktecyv1j  于 2023-05-20  发布在  其他
关注(0)|答案(2)|浏览(177)

我已经在stack overflow和google上跑了好几个小时了。我似乎无法理解如何在 Package 结构中存储函数指针及其参数。
下面的类 Package 了一个函数(在本例中是一个带有模板化返回类型和参数的打包任务)。下面列出了 Package 器的主要部分。
编辑:我不使用std::function的原因是因为 Package 器(ThreadTask) Package 了一个std::packaged_task,它被移动到一个线程安全的双队列中。Packaged_task是可移动构造的,不支持复制,而std::function支持复制。所以我做了一个定制的 Package 。
编译器给出一个错误并声明该函数不接受0个参数。但我不知道如何沿着参数/存储它们。

class ThreadTask {
    struct BaseInterface {

        virtual void Call() = 0;
        virtual ~BaseInterface() {};
    };
    std::unique_ptr<BaseInterface> mImplementation;

    template <typename F, typename...Args>
    struct BaseFunc : BaseInterface {
        F func;

        BaseFunc(F&& f, Args... args) : func(std::move(f)) {}
        void Call() { func(); }
    };
};

我试过用不同的方法来分解这些论点,但似乎都不管用。我想我应该通过std::forward转发它们,但是我不知道如何存储参数

zqdjd7g9

zqdjd7g91#

我推荐使用std::function,但如果你出于某种原因不想使用它,你可以扩展你的当前类,将参数存储在std::tuple中,然后使用std::apply来“解包”并使用存储的参数调用函数。
示例:

class ThreadTask {
public:
    struct BaseInterface {
        virtual ~BaseInterface() = default;
        virtual void operator()() = 0;
    };

    std::unique_ptr<BaseInterface> mImplementation;

    template <typename F, typename... Args>
    struct BaseFunc : BaseInterface {
        BaseFunc(F f, Args... args)
            : func(std::move(f)), m_args{std::move(args)...} {}

        void operator()() override {
            std::apply(func, m_args); 
        }

        F func;
        std::tuple<Args...> m_args;
    };
};

使用示例:

void foo(int x, double y) {
    std::cout << "got " << x << " and " << y << '\n'; 
}

int main() {
    ThreadTask::BaseFunc bf{&foo, 12, 3.14159};

    bf();
}

注意:我将Call()更改为operator()(),这似乎更合适,并将成员设置为public用于演示。
Demo

3phpmpom

3phpmpom2#

您还可以使用std::index_sequence来解包元组并将其传递给函数。

class ThreadTask {
    struct BaseInterface {

        virtual void Call() = 0;
        virtual ~BaseInterface() {};
    };
    std::unique_ptr<BaseInterface> mImplementation;

    template <typename F, typename...Args>
    struct BaseFunc : BaseInterface {
        F func;
        std::tuple<Args...> _args;

        BaseFunc(F&& f, Args... args) : func(std::move(f)), _args(std::make_tuple(args...)) {}
        void Call() { 
            constexpr size_t tuple_size = sizeof...(_args);
            auto index_seq = std::make_index_sequence<tuple_size>();
            CallHelper(index_seq); 
        }
        template<size_t... Is>
        void CallHelper(std::index_sequence<Is...> indexes)
        {
            func(std::get<Is>(_args)...);
        }
    };
};

std::get<Is>(_args)...是一个参数包扩展模式,它将获得std::get<0>(_args), std::get<1>(_args), ..., std::get<n>(_args),这是您最初打算使用的参数。

相关问题