在C ++ 11或更高版本中,是否可以通过lambda实现单方法的纯虚拟C ++接口?

Hon*_*ang 7 c++ lambda c++11

我有一个用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)