请考虑以下代码:
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<lambda_...>
的copy-list-initialization不能使用显式构造函数
使用正确的工厂方法,我可以获得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
类型的局部变量对象?
我的编译器是带有工具集v141的MSVC ++ 2017,因此部分支持C ++ 11/14/17。
答案 0 :(得分:3)
你通过明确声明lambda构造函数来实现自己。删除显式,您的代码应该编译。
请记住,统一列表初始化不适用于显式构造函数。
答案 1 :(得分:2)
从根本上说,你正试图这样做:
struct X {
explicit X(int ) { }
};
X foo() { return {4}; }
这不起作用,因为X
构造函数是explicit
并且您正在进行复制列表初始化。解决方法只是明确构造:
X foo() { return X{4}; }
// ^^^
请注意,在C ++ 17中,这不会导致复制或移动。在C ++ 14之前,这不会产生副本或移动,但移动仍然必须格式良好。
另一个替代方法是从构造函数中删除explicit
标记,这是阻止您返回braced-init-list的原因。
作为旁注,请注意:
template<typename taFunc>
LambdaSubtask<taFunc> MakeLambdaSubtask(BaseTask *pTask, taFunc&& f) { ... }
如果你传递了一个左值函数,那么你将保留对它的引用 - 所以这是你需要担心的额外生命。出于这个原因,通常返回LambdaSubtask<std::decay_t<taFunc>>
。这可确保子任务在其生命周期内具有有效功能。