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
Read File Names from a Directory
Using C Function from Other Package in Rcpp
Does (W)Ifstream Support Different Encodings
C++: Overriding Public\Private Inheritance
Are Class Members Guaranteed to Be Contiguous in Memory
How to Use Non-Default Delimiters When Reading a Text File with Std::Fstream
How Is Heap and Stack Memories Managed, Implemented, Allocated
How to Connect a Signal to a Static Slot Without a Receiver Instance