C Function Pointers with C++11 Lambdas

C function pointers with C++11 lambdas

Using a void* is typical of C callback interfaces to pass some "state" to the function. However, std::function does not need this because std::function supports "stateful functions". So, you could do something like this:

double Integrate(
std::function<double(double)> func,
double a, double b)
{
typedef std::function<double(double)> fun_type;
:::
F.function = [](double x, void* p){
return (*static_cast<fun_type*>(p))(x);
};
F.params = &func;
:::
}

and store a reference to the parameter vector as part of the functor that will be encapsulated in the std::function object or do something like this:

void Another_function()
{
double m = 2;
double b = 3;
auto func = [&](double x){return m*x+b};
auto r1 = Integrate(func,0,3);
:::
}

However, this solution would use rather many indirections. GSL would invoke your lambda. Your lambda would invoke the std::function<>::operator() which in turn would inwoke some kind of virtual function that is used for type erasure which would in turn invoke the actual computation.

So, if you care about performance, you could get rid of a couple of layers there, specifically std::function. Here's a another approach with a function template:

template<class Func>
double Integrate(
Func func,
double a, double b)
{
:::
F.function = [](double x, void* p)->double{
return (*static_cast<Func*>(p))(x);
};
F.params = &func;
:::
}

I guess I would prefer this over the std::function solution.

lambda with conversion function to pointer to function with c++ linkage

What I don't understand is that why a static __invoke function is generated and the "conversion function" is internally calling __invoke (directly as a function pointer) without any parameter which is expected by __invoke?

The conversion function does not "internally call" __invoke, it just returns __invoke, i.e., a pointer to a static member function. Remember that the difference between static and non-static member functions is that the former is not bound to a specific instance of that class, and can hence be treated as ordinary function pointers, as opposed to pointers to members. Have a look at the following example:

struct Test {
void f();
static void g();
};

void (Test::*f)() = &Test::f; // pointer to instance-specific member fct.
void (*g)() = &Test::g; // ordinary function pointer
void (*h)() = Test::g; // no ampersand, this is implicitly a function pointer

The latter is what you intend the result of the conversion to be, and what cppinsights shows you is nothing but a technique to implement this conversion: as the lambda expression has an empty closure, the function object generated by the compiler has no state, and a member function of an object with no state can be a static member function that can bind to an ordinary 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.

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++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.

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.

Passing lambdas as C function pointers

You can make callback template parameter, and specify template argument instead of passing function argument when calling createEditLineCommandDescriptor. E.g.

template<typename Fn, FooMemPtr callback>
tuple<const char*, const char*, Fn> createEditLineCommandDescriptor(const char* command, const char* helpText) {
return make_tuple(command, helpText, [] (EditLine*, int ch) {
Foo foo;
((&foo)->*callback)('a'); // or (foo.*callback)('a');
return ch;
});
}

C++11: Table of Function Pointers, Lambdas

std::function is a mechanism to do type erasure for all things callable.

You can have a collection of std::function and put in function pointers with that signature next to lambdas with that signature. There is a bit of overhead involved compared to using function pointers directly. It's interesting to note that the type of a lambda not specified by the spec and therefore cannot be written down directly, but it can always be put in a std::function wrapper.

When should I choose lambdas over function pointers in C++11?

Chose lambda expression over pointer to function.

I think you should not choose function pointers. Instead, in C++11 you have function objects and lambdas, a lambda being considered an anonymous local function object (though no two lambda expressions are equal; they don't have return types; they are closure types).

I consider them a technical legacy from C that C++ supports. Unless you are working with C or legacy code you might as well consider not to pay too much attention to function pointers.

  • A pointer to function can be cast to a different pointer-to-function type.

  • A lambda has access to its scope's variables, which you can specify in the capture list.

  • A lambda can outlive its caller (pass lambda to different thread, or stored for later usage). And this can be a problem when local variables are captured inappropriately (i.e. by reference).
  • The argument list of a lambda can be omitted. I.e. the shortest lambda is []{}.
  • A lambda expression's return type can be deduced from its body.

When small and used only once: lambda

When not small or reused: function object



Related Topics



Leave a reply



Submit