可在函数签名中使用的可变类型定义

variadic typedef that can be used in function signature

本文关键字:类型 定义 函数      更新时间:2023-10-16

基本上我只是想包装任何可调用的对象和他们的参数在一个任务对象,可以调用以后。下面是我想到的代码:

假设所有可调用类型都有一个成员类型,就像这样定义的:

template<typename TReturn, typename...TArgs>
struct SomeFunction{
    using ArgTypes = TArgs; // won't compile of course
}

任务模板可以这样定义:

template<typename TFunction>
class Task {
public:
    Task(TFunction fun, typename TFunction::ArgTypes...args) // won't compile
        : fun_(fun), args_(args){}
    void operator()()
    {
        fun_(args_...); // won't compile: workaround 1
    }
private: 
    typename TFunction::ArgTypes... args_; // won't compile: workaround 2
    TFunction fun_;
};

问题在于Task的构造函数的定义。有什么办法可以实现吗?当然,我可以将它定义为模板构造函数:

template<typename...TArgs>
Task(TFunction fun, TArgs...args)

但是这样编译器就不会知道TArgs和TFunction::ArgTypes是一样的。因此,当错误的参数传递给它时,错误消息是荒谬的。

解决方案1:c++如何将参数包存储为变量

解决方案2:是否可以"存储";模板参数包而不展开它?

您可以使用std::tuple<TArgs...>来存储参数并在调用操作符中解压缩它们。如果您想以某种方式在函数类型中定义TArgs,则应该在这里将它们定义为元组:

template<typename TReturn, typename...TArgs>
struct SomeFunction{
    using ArgTypesTuple = std::tuple<TArgs...>;
    //                    ^^^^^^^^^^
}

但是,尽管如此,我认为这是不值得的努力保存参数在你的Task对象与大量的样板代码…调用操作符将元组中的参数重构/解包为参数列表,看起来有些难看。

更简单的解决方案是创建一个lambda,它在构建Task对象时捕获参数,它甚至不再需要是模板:

class Task {
public:
    template<typename TFunction, typename ...ArgTypes>
    Task(TFunction fun, ArgTypes... args)
        : fun_([=]{ fun(args...); }) {}
    void operator()()
    {
        fun_();
    }
private: 
    std::function<void()> fun_;
};

你可以做一些改变:

template <typename TReturn, typename...TArgs>
struct SomeFunction{
    using ReturnType = TReturn;
    using ArgTypes = std::tuple<TArgs...>;
};

For Task:

template <typename TFunction, typename TupleArg = typename TFunction::ArgTypes>
class Task;
template <typename TFunction, typename... TArgs>
class Task<TFunction, std::tuple<TArgs...>>
{
public:
    Task(TFunction fun, TArgs...args) : fun_(fun), args_(args...) {}
    void operator()()
    {
        call(make_index_sequence<sizeof...(TArgs)>{});
    }
private:
    template <std::size_t ... Is>
    void call(index_sequence<Is...>)
    {
        fun_(std::get<Is>(args_)...);
    }
private:
    TFunction fun_;
    std::tuple<TArgs...> args_;
};

生活例子