C++将lambda函数保存为成员变量而没有用于优化的函数指针

cow*_*lus 5 c++ optimization lambda inline

我想在C++中编写一个将lambda函数保存为成员变量的类.尽可能高效地做它会很棒.例如,我读了这个线程为什么编译器可以比普通函数更好地优化lambdas?因此我想避免使用函数指针.

到目前为止,我最好的解决方案如下:

template<typename F>
class LambdaClass {
  private:
    F lambdaFunc;
  public:
    LambdaClass(F &_lambdaFunc): lambdaFunc(_lambdaFunc) {}
};
Run Code Online (Sandbox Code Playgroud)

我会用这个类如下:

auto lambdaFunc = [](int _a) -> int { return _a; };
LambdaClass<decltype(lambdaFunc)> lambdaClassObject<decltype(lambdaFunc)>(lambdaFunc);
Run Code Online (Sandbox Code Playgroud)

在我看来,使用它看起来并不好玩.所以我首先感兴趣的是,如果编译器可以内联已保存成员lambda函数的调用,那么这个代码是否有效,以及如何编写这个代码更漂亮?

编辑:我正在使用C++ 11.

asc*_*ler 8

在你的例子中

LambdaClass<decltype(lambdaFunc)> lambdaClassObject<decltype(lambdaFunc)>(lambdaFunc);
Run Code Online (Sandbox Code Playgroud)

第二个模板参数列表是不正确的语法.这需要是公正的

LambdaClass<decltype(lambdaFunc)> lambdaClassObject(lambdaFunc);
Run Code Online (Sandbox Code Playgroud)

因此,我感兴趣的是,如果编译器可以内联已保存成员lambda函数的调用,则此代码是高效的

是的,这个类可以以允许优化的方式使用,就像直接使用lambda一样.模板参数是lambda表达式的确切类型,模板替换在编译时发生,通常给出的结果就像在不使用模板的情况下编写代码一样.

如何编写这段代码更美观?

@ lubgr的回答已经提到了C++ 17"课程模板演绎"和"演绎指南"功能.在C++ 17之前,避免需要指定类模板参数的常用技巧是帮助程序"make function":

template <typename F>
auto makeLambdaClass(F&& func) ->
    LambdaClass<typename std::decay<F>::type>
{ return { std::forward<F>(func); } }
Run Code Online (Sandbox Code Playgroud)

现在你可以做到

auto lambdaFunc = [](int _a) -> int { return _a; };
auto lambdaClassObject = makeLambdaClass(lambdaFunc);
Run Code Online (Sandbox Code Playgroud)

但要更进一步,做到

auto lambdaClassObject = makeLambdaClass( [](int _a) -> int { return _a; } );
Run Code Online (Sandbox Code Playgroud)

也工作,你还需要确保该类有一个接受rvalue的构造函数,而不仅仅是一个非const左值:

template<typename F>
class LambdaClass {
  private:
    F lambdaFunc;
  public:
    LambdaClass(const F &lambdaFunc_): lambdaFunc(lambdaFunc_) {}
    LambdaClass(F &&lambdaFunc_) : lambdaFunc(std::move(lambdaFunc_)) {}
};
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这个类也可以使用一个不是lambda的闭包类型的可调用类,因为lambda只是一种更方便的方法来定义一个类operator():

class UniqueUIntGenerator
{
public:
    unsigned int operator()() const noexcept
    { return num++; }
private:
    static unsigned int num;
};
unsigned int UniqueIntGenerator::num = 0;

LambdaClass<UniqueIntGenerator> gen{UniqueIntGenerator{}};
Run Code Online (Sandbox Code Playgroud)