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.
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.
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.
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.
how to define function pointer compatible with using lambda with capture as call back
You might use std::function
to allow capturing lambdas and other functors and regular function pointers:
void(*funcDX)(CDataExchange* pDX);
void(*funcDXpDoc)(CDataExchange* pDX, CDocument *pDoc);
void(*funcInit)(CWnd *dlgWnd);
void(*funcOK)(CWnd *dlgWnd, CDocument *pDoc);
becomes
std::function<void(CDataExchange*)> funcDX;
std::function<void(CDataExchange*, CDocument*)> funcDXpDoc;
std::function<void(CWnd*)> funcInit;
std::function<void(CWnd*, CDocument*)> funcOK;
You setter/constructor should change pointer function to std::function
too:
void SetInitCallBack(std::function<void(CWnd*)> f) { funcInit = f; }
Else your usage is identical:
if (funcDX) funcDX(pDX);
or
funcInit = nullptr;
Copying c++ lambda to Function Pointer reference
Is the behaviour the same as If I would just define an ordinary function or do I have any side effects here?
Yes, it's the same. A captureless lambda is convertible to a regular function pointer because, to quote the C++ standard ([expr.prim.lambda.closure]/6, emphasis mine):
The closure type for a non-generic lambda-expression with no
lambda-capture has a conversion function to pointer to function with
C++ language linkage having the same parameter and return types as the
closure type's function call operator. The conversion is to “pointer
to noexcept function” if the function call operator has a non-throwing
exception specification. The value returned by this conversion
function is the address of a function F that, when invoked, has the
same effect as invoking the closure type's function call operator.
So while the lambda goes out of scope, that pointer is backed by a proper function, just as if you had written it yourself at file scope. Functions "live" throughout the entire execution of the program, so the pointer will be valid, always.
I can't pass lambda with reference capture
You can only do the above with capture-less lambdas.
See [expr.prim.lambda.closure] (sec 7)
The closure type for a non-generic lambda-expression with no
lambda-capture whose constraints (if any) are satisfied has a
conversion function to pointer to function with C++ language linkage
having the same parameter and return types as the closure type's
function call operator.
Since lambdas are not just ordinary functions and capturing it need to preserve a state,
you can not find any simple or conventional solution to make them assign to function pointers.
To fix, you can use std::function
which will do it by type erasure:
#include <functional> // std::function
int test;
std::function<float(int)> f = [&](int i) -> float {return static_cast<float>(test); };
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.
Why cpp std::function can hold capture-lambda, while function pointer cannot?
Why can a function pointer not hold a lambda with a capture : because a Lambda is NOT a function ,it's an object!
Why can a lambda without a capture be converted to a function pointer ?
A Lambda is just an ordinairy object (a piece of data) of a compiler generated class (with a unique classname that only the compiler knows) with a function-operator member (i.e. auto operator() ( ??? )) that the compiler defines for you with the parameter definitions (if any) you provide. The data-members of a lambda-object are defined by the capture-list and/or usage of variables of its enclosing scope.
All non-static member functions when called on an object get a implicit hidden argument called this. This is also the case when you 'call' the lambda.
Now ,when you don't capture something ,the lambda has no data (empty class) and the compiler doesn't have to generate an implicit this pointer for the call ,which makes the function operator just like an ordinairy function and the compiler can convert it to function pointer.
So it not the lambda that is converted to a function-pointer ,it's the lambda's function-operator that is converted.
Why can std::function hold both : because it's a template and with templates and specializations you can do almost anything.
Related Topics
Measuring Execution Time of a Function in C++
Enum to String in Modern C++11/C++14/C++17 and Future C++20
C++: Life Span of Temporary Arguments
How to Pad an Int With Leading Zeros When Using Cout ≪≪ Operator
Unicode Encoding For String Literals in C++11
Cmake Error At Cmakelists.Txt:30 (Project): No Cmake_C_Compiler Could Be Found
Are There Benefits of Passing by Pointer Over Passing by Reference in C++
Std::Unique_Ptr With an Incomplete Type Won't Compile
Modern Way to Set Compiler Flags in Cross-Platform Cmake Project
How to Make a Http Request With C++
How to Pass a Member Function Where a Free Function Is Expected
C++ Std::Set Update Is Tedious: I Can't Change an Element in Place
Variadic Template Pack Expansion
What Is an 'Undeclared Identifier' Error and How to Fix It
How to Make a Fully Statically Linked .Exe With Visual Studio Express 2005