As we know, non-capturing lambda functors can be converted to function pointers at runtime, but how about compile time? That is, is something similar to the code below possible? Please don't suggest a workaround, like passing the lambda functor as a function parameter, I'd like to know more where/how the C++11 standard forbids this.
template <void(*fptr)()>
void f()
{
// do something
}
int main()
{
auto l([]{});
f<(void(*)())(decltype(l))>();
return 0;
}
The obligatory error with gcc-4.8:
c.cpp: In function 'int main()':
c.cpp:11:7: error: parse error in template argument list
f<(void(*)())(decltype(l))>();
^
c.cpp:11:36: error: statement cannot resolve address of overloaded function
f<(void(*)())(decltype(l))>();
^
Lambda expressions, even with an empty closure, can not be used as a pointer to function template argument because they are temporaries which just happen to convert to some pointer to function. The lambda expression is a temporary according to 5.1.2 [expr.prim.lambda] paragraph 2:
The evaluation of a lambda-expression results in a prvalue temporary. [...]
The conversion to a pointer to function is desribed in paragraph 6:
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.
That is, the conversion doesn't yield a constexpr and, thus, there is no hope to use the resulting pointer to function as a template argument.
As for the reasons the best I could find for now is a statement in N3597 which points towards N2895 which seem to talk about the actual problem but I couldn't locate a detailed discussion. It seems that name-mangling for the functions created by lambda expressions is one of the problems which prohibits using them in certain contexts.
Related
I am primarily making this post to clarify some confusing/misleading information about function pointers that I stumbled upon on Stackoverflow.
Let's begin with an example:
#include <iostream>
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;
void (&fref)()=func;
func();//call through function
(&func)();//call through function pointer
(*fp)();//call through function
fp();//call through function pointer
fref();//call through function
(&fref)();//call through function pointer
}
This prints:
func here
func here
func here
func here
func here
func here
As can be seen a function can be used in place of a function pointer most of the time thanks to function to function pointer decay cppreference.
An lvalue of function type T can be implicitly converted to a prvalue pointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.
But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.
Furthermore this Stackoverflow answer
Note also that you do not need to use the unary * to make the call via the function pointer; both (*p1_foo)(); and (p1_foo)(); have the same result, again because of the function-to-function-pointer conversion.
and this Stackoverflow answer
There's a dual convenience as well: a function pointer in call position is automatically converted to a function value, so you don't have to write * to call through a function pointer.
Make it seem like there exists an implicit function pointer to function conversion.
No
An implicit conversion from function pointer to function doesn't exist.
As of ISO International Standard ISO/IEC 14882:2020(E) – Programming Language C++ there are no mentions of such a conversion.
But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.
This is probably why some SO answers (and even some less known C++ books!) come to the incorrect conclusion that a function pointer is essentially the same as a function and use the function to function pointer decay as evidence. However this implicit conversion only works in one way! Meaning that the quoted section of the first SO answer is incorrect.
Why does the function call succeed anyway?
The reason as to why we can call a function using a function pointer without explicit derefernce actually lies in the way the built in function call operator "()" works cppreference:
The expression that names the function can be
a) lvalue expression that refers to a function
b) pointer to function
c) explicit class member access expression that selects a member function
d) implicit class member access expression, e.g. member function name used within another member function.
Aha! So the function call operator can directly take a function pointer as expression. There is no implicit conversion. If you read the quote from the second SO answer it explicitly mentions that the function pointer needs to be in call position that is called using the function call operator.
This also means that in all contexts outside of a function call a function pointer does need to be dereferenced where a function is expected such as when initializing a function reference:
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;//OK (implicit function to function pointer decay)
void (&&fref1)()=&func;//error: invalid initialization of reference of type 'void (&&)()' from expression of type 'void (*)()'
void (&fref2)()=*fp;//OK
void (&fref3)()=fp;// error: invalid initialization of reference of type 'void (&)()' from expression of type 'void (*)()'
}
I am not sure if I have defined behaviour in the following situation:
My Function pointer type:
typedef void (*DoAfter_cb_type)(void);
The Function which should assign callbacks:
void DoSomething(DoAfter_cb_type & DoAfter_cb)
{
//...
DoAfter_cb = [](){
//...
};
}
Caller:
DoAfter_cb_type DoAfter_cb = nullptr;
DoSomething(DoAfter_cb);
// Here is something that has to be done after DoSomething but before DoAfter_cb.
if( DoAfter_cb != nullptr){
DoAfter_cb();
}
As I learned here lambdas can be implicitly converted to function pointers.
However thoose are still pointers and I fear that something important for calling the lambda is stored on stack and would be out of scope if I just return the function pointer
I have to use function pointers because i do not have access to std::function in my environment.
With std::function I would expect the lambda object to be stored in the reference variable and I would not have any problems.
Is the behaviour the same as If I would just define an ordinary function or do I have any side effects here?
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.
A noob question that probbaly applies to C as well as C++. Let's say I have
void myfunc() {
blah;
}
So, I call this function with:
myfunc();
However, no compiler error is produced when I "call" it with:
myfunc;
Program runs, but myfunc doesn't get called. So, what is C++ interpreting this as?
Now, I'm doing this in the Arduino IDE, all one big lump of code, so I don't get segfaults, etc. So maybe this would throw a runtime error on a dynamically linked host.
myfunc without the parens is the address of the function in memory.
For example, if you have to pass a function to some other function, you would do it with that.
A good example of this is in bsearch in the c standard library, where you need to pass a user defined comparator function in order to do a generic search.
The compiler just evaluates the expression. Since you're evaluating the name of a function, it's basically a no-op.
It's just like this:
int main() {
42; // evaluates 42 but does nothing with it
}
Your compiler should warn you that the result of the expression is unused, anyway.
In C myfunc or any other function name represents the function itself, which will be implicitly converted to a function pointer
Function to pointer
An lvalue of function type T can be implicitly converted to a prvalue pointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.
https://en.cppreference.com/w/cpp/language/implicit_conversion#Function_to_pointer
and () is an operator that when applies to a function pointer or a function object will invoke that function
Built-in function call operator
The function call expressions have the form
E ( A1, A2, A3,... )
where
E is an expression that names a function
A1, A2, A3,... is a possibly empty list of arbitrary expressions, except the comma operator is not allowed at the top level to avoid ambiguity.
The expression that names the function can be
lvalue expression that refers to a function
pointer to function
explicit class member access expression that selects a member function
implicit class member access expression, e.g. member function name used within another member function.
So without the function-call operator myfunc; is just a no-op expression that contains a function pointer. If you've turned on compiler warnings (which you should really do) then they'd shout at you about the issue. GCC says that
statement is a reference, not call, to function 'func' [-Waddress]
warning: statement has no effect [-Wunused-value]
while Clang outputs warning: expression result unused [-Wunused-value]
This question already has an answer here:
Resolving ambiguous overload on function pointer and std::function for a lambda using + (unary plus)
(1 answer)
Closed 9 years ago.
In Stack Overflow question Redefining lambdas not allowed in C++11, why?, a small program was given that does not compile:
int main() {
auto test = []{};
test = []{};
}
The question was answered and all seemed fine. Then came Johannes Schaub and made an interesting observation:
If you put a + before the first lambda, it magically starts to work.
So I'm curious: Why does the following work?
int main() {
auto test = +[]{}; // Note the unary operator + before the lambda
test = []{};
}
It compiles fine with both GCC 4.7+ and Clang 3.2+. Is the code standard conforming?
Yes, the code is standard conforming. The + triggers a conversion to a plain old function pointer for the lambda.
What happens is this:
The compiler sees the first lambda ([]{}) and generates a closure object according to §5.1.2. As the lambda is a non-capturing lambda, the following applies:
5.1.2 Lambda expressions [expr.prim.lambda]
6 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.
This is important as the unary operator + has a set of built-in overloads, specifically this one:
13.6 Built-in operators [over.built]
8 For every type T there exist candidate operator functions of the form
T* operator+(T*);
And with this, it's quite clear what happens: When operator + is applied to the closure object, the set of overloaded built-in candidates contains a conversion-to-any-pointer and the closure type contains exactly one candidate: The conversion to the function pointer of the lambda.
The type of test in auto test = +[]{}; is therefore deduced to void(*)(). Now the second line is easy: For the second lambda/closure object, an assignment to the function pointer triggers the same conversion as in the first line. Even though the second lambda has a different closure type, the resulting function pointer is, of course, compatible and can be assigned.
I have a class db_interface. And defined a lambda type:
typedef void (*db_interface_lambda)();
When I create lambda in class in such way: [](){ /* do something */ }, it has good type (db_interface_lambda), but when I use [this](){ /* do something */ }, the compiler starts to shout at me.
cannot convert ‘db_interface::db_interface(std::ifstream&)::<lambda()>’ to ‘std::map<std::basic_string<char>, void (*)()>::mapped_type {aka void (*)()}’ in assignment
How to solve that problem? What is the correct type?
Because lambdas are only implicitly convertible to function pointers if and only if they do not capture anything.
§5.1.2 [expr.prim.lambda] p6
The closure type for a lambda-expression with no lambda-capture ([] is empty) 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.
Btw, what you typedef'd there is a function pointer, not a lambda type. Lambda expressions have a unique, unnamed, nonunion class type. You can not name them.
§5.1.2 [expr.prim.lambda] p3
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type
You're trying to call something that wants a function pointer. A captureless lambda can be converted to a function pointer automatically, but once you write [this] it ceases to be captureless - you're capturing this, so it's an error.
The solution is to change the type to be a std::function, not a pointer to a function. std::function erases the type of the "functor" it "wraps" so you can still pass a function pointer as well as a lamba with a capture.
Lambdas that do not capture anything are essentially free functions, and thus they are convertible to ordinary function pointers.
Lambdas that do capture are essentially full classes, and they cannot simply be converted to a free-function pointer. (A capturing lambda is really essentially the same predicate functor class that you would have written in C++ before we had lambdas.)
Either version of lambda is convertible to std::function<void()>, which is what the mapped type of your map should be.