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

后端 未结 4 1847
北海茫月
北海茫月 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 <iostream>
    
    template <typename T>
    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<char, std::char_traits<char> >::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.

    0 讨论(0)
  • 2020-12-31 08:38

    I do not know enough of the standard to say whether this is my compilers fault not implementing it properly or if it's actually the standard, but with VS2015 you cannot generate a compile-time constant lambda expression. And templates only take compile time constants, so no lambdas.

    However, you don't need it to be a template if you want to pass a lambda. It's perfectly possible without:

    #include <functional>
    
    int function(std::function<int(int)> const& f, int a)
    {
        f(a);
    }
    
    int test(int a)
    {
        return a;
    }
    
    int main()
    {
        auto lambda = [](int a) -> int { return a; };
    
        function(test, 1);
        function(lambda, 1);
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-31 08:42

    This is only because "You cannot use the name or address of a local variable as a template argument.". If you want to make a global static lambda, go refer to http://pfultz2.com/blog/2014/09/02/static-lambda/ you may find what you want.

    0 讨论(0)
  • 2020-12-31 08:45

    This is because the lambda as its own type.
    You have templatize function() on the type of the function passed.

    template<typename F>
    int function(F foo, int a) {
        return foo(a);
    }
    
    int test(int a) {
        return a;
    }
    
    int main()
    {
        // function will work out the template types
        // based on the parameters.
        function(test, 1);
        function([](int a) -> int { return a; }, 1);
    }
    
    0 讨论(0)
提交回复
热议问题