Passing Capturing Lambda as Function Pointer

Passing capturing lambda as function pointer

A lambda can only be converted to a function pointer if it does not capture, from the draft C++11 standard section 5.1.2 [expr.prim.lambda] says (emphasis mine):

The closure type for a lambda-expression with no lambda-capture has a
public non-virtual non-explicit const conversion function to pointer
to function
having the same parameter and return types as the closure
type’s function call operator. The value returned by this conversion
function shall be the address of a function that, when invoked, has
the same effect as invoking the closure type’s function call operator.

Note, cppreference also covers this in their section on Lambda functions.

So the following alternatives would work:

typedef bool(*DecisionFn)(int);

Decide greaterThanThree{ []( int x ){ return x > 3; } };

and so would this:

typedef bool(*DecisionFn)();

Decide greaterThanThree{ [](){ return true ; } };

and as 5gon12eder points out, you can also use std::function, but note that std::function is heavy weight, so it is not a cost-less trade-off.

How to get a function pointer from lambda expressions or so? [duplicate]

If you cannot change the C API then I don't think you can do much about this situation. Because C functions require all the information they require to be passed in as function parameters.

You can convert lambdas to function pointers with the following

void (*ptr) () = []() {}

Lambdas without any capture can be implicitly converted to function pointers. But lambdas which capture values cannot be converted to function pointers since they have extra state (in the form of member variables).

The usual way to solve this problem in C is with void* parameters. Take a look at the pthread_create function. The thread start function accepts a function with a void* parameter which points to a "context". This context in your situation can be something like the instance you are calling the method on.

But if you cannot change the C API, then I am afraid you cannot do much regarding function pointers. The only thing you can do is to make the variables global and then use those to call those methods in the function pointer.

C++: Passing lambda pointer as a function pointer

Your BrentsFindRoot takes a stateless function pointer.

Your lambda has state.

These are not compatible. Both conceptually and syntactically.

BrentsFindRoot( double (*f)(void const*, double), void const*, double a, double b, double tol )

this is how the signature would change if you added state and wanted it to remain a pure C function. Then passing a lambda works conceptually, but the syntax is awkward. If you do not mind C++ in your root finder:

BrentsFindRoot( std::function<double(double)> f, double a, double b, double tol )

Alternatively, you can shoe-horn state into a stateless function pointer via table/global state tricks. You could also make the lambda stateless by taking and storing something equivalent to a as a compile time parameter.

But just do the std::function version.

if BrentsFindRoot is a header only function, you can use a template

template<class F>
void BrentsFindRoot( F f, double, double, double );

a final option is to find or write a function_view type; this can be more efficient than a std::function by avoiding storage.

union function_state {
void* pvoid;
void(* pfvoid)();
function_state(void* p=nullptr):pvoid(p) {}
template<class R, class...Args>
function_state(R(*pf)(Args...)):pfvoid(reinterpret_cast<void(*)()>(pf)) {}
};
template<class Sig>
struct function_view;
template<class R, class...Args>
struct function_view<R(Args...)> {
function_state state;
R(*pf)(function_state, Args&&...args) = nullptr;

R operator()(Args...args)const {
return pf(state, std::forward<Args>(args)...);
}
function_view(function_view const&)=default;
function_view& operator=(function_view const&)=default;
explicit operator bool() const{ return pf; }

function_view( R(*f)(Args...) ):
state(f),
pf([](function_state s, Args&&...args)->R{
return reinterpret_cast<R(*)(Args...)>(s.pfvoid)( std::forward<Args>(args)... );
})
{}


template<class F, std::convertible_to<R> FR=std::invoke_result_t< F, Args... >>
requires (!std::is_same_v<R,void>)
function_view( F&& f ):
state((void*)std::addressof(f)),
pf([](function_state s, Args&&...args)->R{
return (*static_cast<F*>(s.pvoid))( std::forward<Args>(args)... );
})
{}
template<class F>
requires (std::is_same_v<R, void>)
function_view( F&& f ):
state((void*)std::addressof(f)),
pf([](function_state s, Args&&...args)->void{
(*static_cast<F*>(s.pvoid))( std::forward<Args>(args)... );
})
{}


template<std::convertible_to<R> R0, std::constructible_from<Args>...As>
requires (!std::is_same_v<R,void>)
function_view( R0(*f)(As...) ):
state(f),
pf([](function_state s, Args&&...args)->R{
return reinterpret_cast<R0(*)(As...)>(s.pfvoid)( std::forward<Args>(args)... );
})
{}
template<class R0, std::constructible_from<Args>...As>
requires (std::is_same_v<R, void>)
function_view( R0(*f)(As...) ):
state(f),
pf([](function_state s, Args&&...args)->void{
reinterpret_cast<R0(*)(As...)>(s.pfvoid)( std::forward<Args>(args)... );
})
{}
};

but that probably isn't something you want to write quite yet.

C++ lambda with captures as a function pointer

Since capturing lambdas need to preserve a state, there isn't really a simple "workaround", since they are not just ordinary functions. The point about a function pointer is that it points to a single, global function, and this information has no room for a state.

The closest workaround (that essentially discards the statefulness) is to provide some type of global variable which is accessed from your lambda/function. For example, you could make a traditional functor object and give it a static member function which refers to some unique (global/static) instance.

But that's sort of defeating the entire purpose of capturing lambdas.

Obtaining function pointer to lambda?

This fails:

auto *b = [](int i) { return i; };

because the lambda is not a pointer. auto does not allow for conversions. Even though the lambda is convertible to something that is a pointer, that's not going to be done for you - you have to do it yourself. Whether with a cast:

auto *c = static_cast<int(*)(int)>([](int i){return i;});

Or with some sorcery:

auto *d = +[](int i) { return i; };

C++11 lambdas to Function Pointer

I can not use the STL std::function (because my program does not use C++ RTTI and EXCEPTIONS runtime)

Then you may need to write your own equivalent to std::function.

The usual implementation of type erasure for std::function doesn't need RTTI for most of its functionality; it works through regular virtual function calls. So writing your own version is doable.

Indeed, the only things in std::function that need RTTI are the target_type and target functions, which are not the most useful functions in the world. You might be able to just use std::function without calling these functions, assuming that the implementation you're using doesn't need RTTI for its usual business.

Typically, when you disable exception handling, the program simply shuts down and errors out when encountering a throw statement. And since most of the exceptions that a std::function would emit aren't the kind of thing you would be able to recover from (calling an empty function, running out of memory, etc), you can probably just use std::function as is.

Return lambda with capture from a function in c++11

std::function<void()> is not a function pointer. std::function<void()> can store more than just function pointers.

If you'd try to return a function pointer void(*)() then the code would fail to compile, because lambdas with capture do not have a conversion to function pointer.

As parameter is passed and capture by referene and var is still in scope while you call foo() the code is fine.

C++17 decorate lambda or member function with non-capturing lambda

First, your decorate_lambda is buggy: it silently breaks if you call it with a stateful callable. As a simple check, you could allow callables only if std::is_empty_v is true.



The end result that I would like is to roll decorate_lambda and decorate_memfn into a single decorate(lambda_or_memfn) function

You can use std::integral_constant

template<auto x>
inline constexpr std::integral_constant<decltype(x), x> constant{};

template<typename T, typename F, F T::* x>
auto decorate(std::integral_constant<F T::*, x>)
{
return [](auto&&... args) {
return 100 + std::mem_fn(x)(decltype(args)(args)...);
};
}

auto d = decorate(constant<&Worker::work>);

Wrapping a capturing lambda as a function pointer in a template function

The issue is that decltype(closure) inside wrap_closure is std::function<void(Statistics)>, while the original closure whose address you pass in is a lambda. They are not the same type, thus the static_cast through void * has undefined behaviour.

You can fix it either way, either keep the std::function but ensure that both sides agree:

std::function<void(Statistics)> f = closure;
call_callback (wrap_closure(f), &f);

... which is quite brittle as you've noticed, or get rid of std::function and use the type of closure as-is:

template <typename... T, typename Callable>
auto wrap_closure(Callable const &) -> void(*)(T..., void*)
{
return +[](T... data, void* userdata) {
(*static_cast<Callable*>(userdata))(data...);
};
}

// Usage
call_callback (wrap_closure<Statistics>(closure), &closure);

Variadic salt and pepper free of charge.

non-capturing lambda and function pointer as parameter in overloaded function ambiguity

You can use technique described in this question with some small postprocessing.

Minimal example:

template<typename Ret, typename Arg>
Arg argument_type(Ret(*)(Arg));

template<typename Ret, typename Fn, typename Arg>
Arg argument_type(Ret(Fn::*)(Arg) const);

template<typename Fn>
auto argument_type(Fn) -> decltype(argument_type(&Fn::operator()));

template<typename Arg, typename Fn>
struct argument {
static_assert(std::is_invocable_v<Fn, Arg>);
using type = Arg;
};

template<typename Fn>
struct argument<void, Fn>{
using type = decltype(argument_type(std::declval<Fn>()));
};

template<typename T = void, typename Fn>
void test(Fn fn) {
using Arg = std::decay_t<typename argument<T, Fn>::type>;
std::cout << "Arg = " << boost::typeindex::type_id_with_cvr<Arg>().pretty_name()
<< std::endl;
}

int main() {
int capturing_var;

test<int>([capturing_var](const int& x) {}); // Arg = int
test<int>([](const int& x) {}); // Arg = int
test([](const int& x) {}); // Arg = int
test(+[](const int& x) {}); // Arg = int
test<int>([](auto x) {}); // Arg = int
}

If the argument type cannot be deduced, e.g., for a variadic lambda, it has to be provided (last example).



Related Topics



Leave a reply



Submit