How I can pass lambda expression to c++ template as parameter

后端 未结 4 1848
北海茫月
北海茫月 2020-12-31 08:03

I have a template that accepts a function as an argument.

When I try to pass a lambda expression it does not compile.

typedef int (*func)(int a);
te         


        
4条回答
  •  伪装坚强ぢ
    2020-12-31 08:38

    A lambda is not a function pointer! A lambda is an instance of compiler generated class!

    However, a non capturing lambda may be converted to a function pointer using it's operator+

    Here's an example:

    int main() {
        auto lambda = [](int a) { return a; };
    
        func ptr = +lambda; // this would work
    
        return 0;
    }
    

    Sadly, the operator+ won't even work in your case because it has not been declared as constexpr, so you can't use it in a template parameter.

    A fix to your case would be to use a free function... until N4487 is not accepted, you can't expect to pass lambda as template parameter.

    Another fix would be to create your own functor instead of a lambda:

    struct LambdaType {
        constexpr LambdaType() = default;
    
        int operator()(int a) {
            return run(a);
        }
    
        // this is a non-capturing lambda, the operator can be
        // in a static function
        static int run(int a) {
            return a;
        }
    };
    
    int main() {
        LambdaType lambda;
    
        function<&LambdaType::run>(1); // ---> this is working
    
        return 0;
    }
    

    This solution is not quite appealing, but it might be useful if LambdaType is hidden in a cpp file.

    If your goal is only the compiler to be able to inline your code, you can use templates to pass the lambda around:

    #include 
    
    template 
    int function(T foo, int a) {
        return foo(a);
    }
    
    int main() {
        int a;
        std::cin >> a;
    
        int b = function([](int a) { return a; }, a);
    
        return b;
    }
    

    Since the compiler knows the type of T for each instanciation, a good compiler should be able to optimize out the lambda.

    With clang, the third option gives the following assembly:

    main:                               # @main
        pushq   %rax
        leaq    4(%rsp), %rsi
        movl    std::cin, %edi
        callq   std::basic_istream >::operator>>(int&)
        movl    4(%rsp), %eax    # this is the call to the function
        addq    $8, %rsp
        retq
    
        pushq   %rax
        movl    std::__ioinit, %edi
        callq   std::ios_base::Init::Init()
        movl    std::ios_base::Init::~Init(), %edi
        movl    std::__ioinit, %esi
        movl    $__dso_handle, %edx
        popq    %rax
        jmp     __cxa_atexit            # TAILCALL
    

    I used -std=c++14 -Ofast -march=native as flags.

提交回复
热议问题