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
Delete VS Delete[] Operators in C++
Determine If Two Rectangles Overlap Each Other
Purpose of Unions in C and C++
What's the Difference Between Constexpr and Const
Why C++11 In-Class Initializer Cannot Use Parentheses
How to Print Function Pointers With Cout
Undefined Behavior and Sequence Points
Difference Between the Dot (.) Operator and -≫ in C++
How to Find Out If an Item Is Present in a Std::Vector
A Positive Lambda: '+[]{}' - What Sorcery Is This
What Is "Rvalue Reference For *This"
Using Base Pointer Register in C++ Inline Asm
Parsing a Comma-Delimited Std::String
Why Is the Use of Rand() Considered Bad