考虑以下代码:
class BaseTask {
// Implementation here
};
class BaseSubtask {
BaseTask *_pTask;
public:
explicit BaseSubtask(BaseTask *pTask) : _pTask(pTask) { }
virtual void Run() = 0;
// The rest of implementation here.
};
template<typename taFunc> class LambdaSubtask {
taFunc _f;
public:
explicit LambdaSubtask(BaseTask *pTask, taFunc&& f)
: BaseSubtask(pTask), _f(std::forward<taFunc>(f))
{ }
LambdaSubtask(const LambdaSubtask&) = delete;
LambdaSubtask& operator=(const LambdaSubtask&) = delete;
LambdaSubtask(LambdaSubtask&&) = delete;
LambdaSubtask& operator=(LambdaSubtask&&) = delete;
virtual void Run() override final { _f(); }
// The rest of implementation here
};
因为我不能在不指定其模板类型参数的情况下声明
LambdaSubtask
对象,并且由于是lambda而不能指定其模板类型参数,所以我尝试实现一个工厂方法:template<typename taFunc> inline LambdaSubtask<taFunc>
MakeLambdaSubtask(BaseTask *pTask, taFunc&& f) {
return { pTask, std::forward<taFunc>(f) };
}
不幸的是,这会导致编译错误:
使用适当的工厂方法,我可以得到一个
LambdaSubtask
对象,如下所示:BaseTask task; // Initialization of the task is skipped in the example
auto&& lst = MakeLambdaSubtask(&task, [/* Capture here*/]() {
// Implementation here
});
所以基本上我想要一个
LambdaSubtask
类型的局部变量对象,模板类型是lambda。我想避免额外复制任何东西。我肯定要避免使用std::function
,因为我的基准测试表明它非常慢。您知道如何实现适当的工厂方法或以其他方式获取
LambdaSubtask
类型的局部变量对象吗?我的编译器是MSVC++ 2017,具有工具集v141,因此部分支持C++ 11/14/17。
最佳答案
从根本上讲,您正在尝试执行以下操作:
struct X {
explicit X(int ) { }
};
X foo() { return {4}; }
那是行不通的,因为
X
构造函数是explicit
,并且您正在执行复制列表初始化。解决方法是显式构造:X foo() { return X{4}; }
// ^^^
请注意,在C++ 17中,这不会引起复制或移动。在C++ 14之前,这既不会引起复制也不会产生任何举动,但是举动仍然必须格式正确。
另一种选择是从构造函数中删除
explicit
标记,这是阻止您返回支撑初始列表的原因。作为旁注,请注意以下事项:
template<typename taFunc>
LambdaSubtask<taFunc> MakeLambdaSubtask(BaseTask *pTask, taFunc&& f) { ... }
如果您传入的是左值函数,则将保留对其的引用-因此,这是您必须担心的额外寿命。因此,通常返回
LambdaSubtask<std::decay_t<taFunc>>
。这样可以确保子任务在其生命周期内具有有效的功能。