基本上我只想将任何可调用对象及其参数包装在以后可以调用的Task obj中。以下是我想到的代码:
让我们说所有那些可调用类型都有一个成员类型可能看起来像是这样定义的:
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++ How to store a parameter pack as a variable
解决方法2:Is it possible to "store" a template parameter pack without expanding it?
答案 0 :(得分:2)
您可以使用std::tuple<TArgs...>
存储参数并将其解压缩到call-operator中。如果要在函数类型中以某种方式定义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_;
};
答案 1 :(得分:1)
您可以对某些更改做些什么:
template <typename TReturn, typename...TArgs>
struct SomeFunction{
using ReturnType = TReturn;
using ArgTypes = std::tuple<TArgs...>;
};
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_;
};