Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a function with std::function as argument with a lambda

Tags:

c++

c++11

The basis from my question I took from here: Failure to deduce template argument std::function from lambda function The question in this thread is: Why this code can't pass the lambda to the function:

#include <iostream>
#include <functional>

template <typename T>
void call(std::function<void(T)> f, T v)
{
    f(v);
}

int main(int argc, char const *argv[])
{
    auto foo = [](int i) {
        std::cout << i << std::endl;
    };
    call(foo, 1);
    return 0;
}

The answer in this thread is, since a lambda isn't a std::function. But why is this code compiling:

#include <iostream>
#include <functional>

template <typename T>
void call(std::function<void(T)> f, T v)
{
    f(v);
}

int main(int argc, char const *argv[])
{
    auto foo = [](int i) {
        std::cout << i << std::endl;
    };
    call({foo}, 1); // changed foo to {foo}
    return 0;
}
like image 376
JulianH Avatar asked Aug 29 '19 08:08

JulianH


People also ask

How to pass lambda as function argument C++?

A lambda that contains move-only variables is only accepted by the following variants: template <typename F> void use_func(F& func) template <typename F> void use_func(F&& func)

How do you pass a lambda function as an argument?

Passing Lambda Expressions as Arguments You can pass lambda expressions as arguments to a function. If you have to pass a lambda expression as a parameter, the parameter type should be able to hold it. If you pass an integer as an argument to a function, you must have an int or Integer parameter.

What is std:: invoke?

The std::invoke() method can be used to call functions, function pointers, and member pointers with the same syntax: #include <iostream>#include <functional>using namespace std;void globalFunction( ) { cout << "globalFunction ..." <<

What is the use of lambda functions in C++?

One of the new features introduced in Modern C++ starting from C++11 is Lambda Expression. It is a convenient way to define an anonymous function object or functor. It is convenient because we can define it locally where we want to call it or pass it to a function as an argument.


1 Answers

As written in the linked answer, the first version does not compile, because template argument deduction fails for the first argument; a lambda is never an std::function<void(T)>.

The second version compiles, because, by writing {foo}, std::function<void(T)> becomes a non-deduced context. So deduction can no longer fail for the first argument, as it isn't even attempted. So T is deduced as int solely from the second argument, and the call succeeds, because the lambda is convertible to an std::function<void(int)>.

From [temp.deduct.type]:

The non-deduced contexts are:

  • ...
  • A function parameter for which the associated argument is an initializer list but the parameter does not have a type for which deduction from an initializer list is specified.
like image 59
Mark Avatar answered Oct 04 '22 09:10

Mark