Passing a Lambda into a Function Template

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

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.

Passing a lambda into a function template

Your function binsearch takes a function pointer as argument. A lambda and a function pointer are different types: a lambda may be considered as an instance of a struct implementing operator().

Note that stateless lambdas (lambdas that don't capture any variable) are implicitly convertible to function pointer. Here the implicit conversion doesn't work because of template substitution:

#include <iostream>

template <typename T>
void call_predicate(const T& v, void (*predicate)(T)) {
std::cout << "template" << std::endl;
predicate(v);
}

void call_predicate(const int& v, void (*predicate)(int)) {
std::cout << "overload" << std::endl;
predicate(v);
}

void foo(double v) {
std::cout << v << std::endl;
}

int main() {
// compiles and calls template function
call_predicate(42.0, foo);

// compiles and calls overload with implicit conversion
call_predicate(42, [](int v){std::cout << v << std::endl;});

// doesn't compile because template substitution fails
//call_predicate(42.0, [](double v){std::cout << v << std::endl;});

// compiles and calls template function through explicit instantiation
call_predicate<double>(42.0, [](double v){std::cout << v << std::endl;});
}

You should make your function binsearch more generic, something like:

template <typename T, typename Predicate>
T binsearch(const std::vector<T> &ts, Predicate p) {

// usage

for(auto& t : ts)
{
if(p(t)) return t;
}

// default value if p always returned false

return T{};
}

Take inspiration from standard algorithms library.

C++ Pass lambda to template parameter

Lambdas in C++14, including their conversion to function pointers, are not constexpr.

In C++17, this is going to change. There are no stable compilers with that feature implemented that I'm aware of (if you find one, can you mention it in the comments below?).

At that point

constexpr auto tmp = []() -> void { std::cout << "Hello world\n"; };
function<+tmp>();

will definitely work. I am uncertain if

function<+[]() -> void { std::cout << "Hello world\n"; }>()

would work; there are some rules about lambdas in unevaluated contexts and inside template argument lists that may be separate from the constexpr lambda problem and may apply here.

We can hack it in C++14.

Create a template class that stores a static copy of a lambda and exposes a static function with the same signature (f_ptr) that calls that static copy of a lambda.

Instantiate it once globally with your lambda.

Pass a pointer to the f_ptr to your template.

So:

template<class L> struct stateless; // todo
template<class L> stateless<L> make_stateless(L l){return std::move(l);}

auto foo = make_stateless( []() -> void { std::cout << "Hello world\n"; } );

function< &foo::f_ptr >();

this is almost certainly not what you want.

Pass C++20 Templated Lambda to Function Then Call it

The issue is that lambdas are not class templates, they're just regular classes where the member call operator, i.e. operator() is templated.

When the template parameters are deduced for a generic lambda, this distinction is not noticeable (which is a very good thing).

So in your example, lambda is not a class template, but you are using syntax that would be used for a class, not a member function.

If you want to specify the template parameters for a lambda explicitly, you'll need to say that you're calling the member operator() of lambda, and you'll need to say that it's a template to disambiguate.

lambda.template operator()<Alignment::eight>(t.data(), t.size());

Here's the version of your code that compiles.

Passing Type Into Lambda Function In C++ Template

The problem is the rigidity of CLang compilers with respect to the standard.

The problem is not the type(that is correct), the problem is that you have to put typename before template dependant types.

However the best solution is to use auto to let the compiler deduce the type itself.

Passing a lambda function to a template method

The function call tries to deduce T from both the first and second function parameter.

It will correctly deduce T from the first parameter, but fail to deduce it from the second parameter, because the second function argument is a lambda type, not a std::function type.

If deduction isn't possible from all parameters that are deduced context, deduction fails.

You don't really need deduction from the second parameter/argument here, since T should be fully determined by the first argument. So you can make the second parameter a non-deduced context, for example by using std::type_identity:

void eraserFunction(std::vector<T>& array, std::type_identity_t<std::function<int(const T&, const T&)>> func)

This requires C++20, but can be implemented easily in user code as well if you are limited to C++11:

template<typename T>
struct type_identity { using type = T; };

and then

void eraserFunction(std::vector<T>& array, typename type_identity<std::function<int(const T&, const T&)>>::type func)

std::identity_type_t<T> is a type alias for std::identity_type<T>::type. Everything left to the scope resolution operator :: is a non-deduced context, which is why that works.


If you don't have any particular reason to use std::function here, you can also just take any callable type as second template argument:

template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)

This can be called with a lambda, function pointer, std::function, etc. as argument. If the argument is not callable with the expected types, it will cause an error on instantiation of the function body containing the call. You can use SFINAE or since C++20 a type constraint to enforce this already at overload resolution time.

How to pass lambda expression as parameters in C++

A lambda is a different type than std::function. You can add another template parameter to allow passing anything callable (which lambdas are) as the comparator function.

template <typename T, typename Predicate>
int count_if(typename linkList<T>::iterator it_start, typename linkList<T>::iterator it_end, Predicate&& cmp ){
int ret = 0;
while(it_start != it_end){
if(cmp(*it_start)) ++ret;
++it_start;
}
return ret;
}

How to pass a lambda to a template paramater

In C++11? With a lambda as template parameter?

Given that a lambda (before C++20) can't be used in an unevaluated context (so in a decltype()) and can't be default constructed, I don't see a way.

The best I can imagine, in C++11, to reproduce something similar is something as follows

template <typename T, typename F = std::function<std::string(T const &)>>
std::string func (T const & t, F f = [](const T &t){return std::string{t};})
{ return f(t); }

that you can call with only the first argument

func("abc");

given that you accept the default lambda (but is saved as a std::function).

You can also pass another lambda, if you don't like the default one

func(1, [](int const &){ return "one"; });

but as a traditional argument, not as template parameter.

C++ lambda as std::function in template function

What about simply as follows ?

template <typename F>
auto Context::executeTransient (F const & commands) {
...
auto result = commands(commandBuffer);
...
return result;
}

This way your method accept both standard functions and lambdas (without converting them to standard functions, that is preferable, from the performance point of view (as far as I know)) and the return type is deduced from the use (auto).

In you need to know the R type inside the method, you can apply decltype() to result

     auto result = commands(commandBuffer);

using R = decltype(result);

If you need to know the R type as template parameter of the method, its a little more complex because involve std::declval() and, unfortunately, add redundancy

template <typename F,
typename R = decltype(std::declval<F const &>()(commandBuffer))>
R Context::executeTransient (F const & commands) {
...
R result = commands(commandBuffer);
...
return result;
}


Related Topics



Leave a reply



Submit