c ++:使用模板将任何lambda包装在另一个lambda中

时间:2019-06-05 13:38:49

标签: c++ templates lambda

我想创建一个可以包装任何lambda的函数,以便在其上记录开始/结束调用。

以下代码适用,除了:

  1. 具有捕获的任何lambda

  2. 任何返回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);

}

有没有办法做到这一点?宏也是可以接受的

2 个答案:

答案 0 :(得分:4)

使用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

答案 1 :(得分:3)

该代码具有未定义的行为。

auto logLambda(T lambda) {
    return [&lambda]

您正在通过引用捕获局部参数。