我有一个用C ++ 98编写的大型C ++库,该库大量使用C ++接口(准确地说,只有纯虚函数的C ++类)进行事件处理。现在看到我的代码是由C ++ 11/14编译器编译的,我在考虑是否可以通过使用C ++ 11 lambda代替接口实现来减少样板代码。
在我的库中,有些C ++接口只有一个方法,例如,以下用于定义简单任务的接口:
class SimpleTask
{
public:
void run();
};
Run Code Online (Sandbox Code Playgroud)
我的意图是使用C ++ lambda替换旧的单方法接口实现代码,如下所示:
void myFunction()
{
...
class MySimpleTask : SimpleTask //An inline class to implement the iterface
{
public:
void run()
{
//Do somthing for this task
...
delete this; //Finally, destroy the instance
}
};
MySimpleTask * myThreadTask = new MySimpleTask();
Thread myThread(L"MyTestingThread", myThreadTask);
myThread.start();
...
}
Run Code Online (Sandbox Code Playgroud)
在Java 8中,我们可以使用Java lambda来实现单方法接口,以比使用匿名类更简洁地编写代码。我在C ++ 11中做了一些研究,发现没有类似的东西。
由于我的库的事件处理代码是按面向对象的模式设计的,而不是按功能编码的样式设计的,是否有办法使用lambda来帮助减少那些单方法接口实现代码?
Hol*_*olt 11
您可以创建一个包装器,例如:
class SimpleTask {
public:
virtual void run() = 0;
};
// This class wraps a lambda (or any callable) and implement the run()
// method by simply calling the callable.
template <class T>
class LambdaSimpleTask: public SimpleTask {
T t;
public:
LambdaSimpleTask(T t) : t(std::move(t)) { }
virtual void run() {
t();
}
};
template <class T>
auto makeSimpleTask(T &&t) {
// I am returning a dynamically allocated object following your example,
// but I would rather return a statically allocated one.
return new LambdaSimpleTask<std::decay_t<T>>{std::forward<T>(t)};
}
Run Code Online (Sandbox Code Playgroud)
然后创建任务:
auto task = makeSimpleTask([]() { });
Thread myThread(L"MyTestingThread", task);
Run Code Online (Sandbox Code Playgroud)
请注意,您仍然需要makeXXX为每个接口都有一个包装器和一个函数。在C ++ 17及更高版本中,可以makeXXX通过使用类模板参数推导来摆脱此功能。摆脱包装是不可能的,但是您可以通过将一些东西封装在宏中来减少样板代码。
这是一个示例宏(不完美),可用于减少样板代码:
#define WRAPPER_FOR(C, M, ...) \
template <class T> \
class Lambda##C: public C { \
T t; \
public: \
Lambda##C(T t) : t(std::move(t)) { } \
virtual M { return t(__VA_ARGS__); } \
}; \
template <class T> auto make##C(T &&t) { \
return Lambda##C<std::decay_t<T>>{std::forward<T>(t)}; }
Run Code Online (Sandbox Code Playgroud)
然后:
class SimpleTask {
public:
virtual void run() = 0;
};
class ComplexTask {
public:
virtual int run(int, double) = 0;
};
WRAPPER_FOR(SimpleTask, void run());
WRAPPER_FOR(ComplexTask, int run(int a, double b), a, b);
Run Code Online (Sandbox Code Playgroud)