我想做一个可以包装任何lambda来记录开始/结束调用的函数。

以下代码适用于以下内容:


任何具有捕获的lambda
任何返回void的lambda(尽管可以通过编写第二个函数来轻松解决此问题)


#include <iostream>
#include <functional>

template <class T, class... Inputs>
auto logLambda(T lambda) {
    return [&lambda](Inputs...inputs) {
        std::cout << "STARTING " << std::endl;
        auto result = lambda(inputs...);
        std::cout << "END " << std::endl;
        return result;
    };
}

int main() {
    int a = 1;
    int b = 2;

    // works
    auto simple = []() -> int {
        std::cout << "Hello" << std::endl; return 1;
    };
    logLambda(simple)();

    // works so long as explicit type is declared
    auto with_args = [](int a, int b) -> int {
        std::cout << "A: " << a << " B: " << b << std::endl;
        return 1;
    };
    logLambda<int(int, int), int, int>(with_args)(a, b);

    // Does not work
    // error: no matching function for call to ‘logLambda<int(int), int>(main()::<lambda(int)>&)’
    auto with_captures = [&a](int b) -> int {
        std::cout << "A: " << a << " B: " << b << std::endl;
        return 1;
    };
    logLambda<int(int), int>(with_captures)(b);

}


有什么办法吗?宏也是可以接受的

最佳答案

使用Raii来处理void和non-void返回类型,
并按值捕获函子,以避免悬挂参考,
并使用通用lambda来避免必须指定自己的参数

结果如下:

template <class F>
auto logLambda(F f) {
    return [f](auto... args) -> decltype(f(args...)) {
        struct RAII {
            RAII()  { std::cout << "STARTING " << std::endl; }
            ~RAII() { std::cout << "END " << std::endl; }
        } raii;

        return f(args...);
    };
}


呼叫看起来像:

const char* hello = "Hello";
logLambda([=](const char* s){ std::cout << hello << " " << s << std::endl; })("world");


Demo

10-07 18:59
查看更多