#include <iostream>
void PrintTheValue(int(*func)(int a));
int main(int argc, char **argv) {
PrintTheValue([](int a) {return a; });
return 0;
}
void PrintTheValue(int(*func)(int a)) {
std::cout << *func << std::endl;
}
In my concept of understanding the func, it would be a pointer to an int passed by value. But in this case I'm passing a lambda which doesn't seem to be called anywhere. (So there isn't any value at all?)
When I run this, it doesn't break the program, but instead printed 00EE6F80.
What does this address mean? I have no idea how to interpret it.
In my concept of understanding the func, it would be a pointer to an int passed by value.
func is a pointer to function, which takes an int and returns int.
But in this case I'm passing a lambda which doesn't seem to be called anywhere.
You're passing a lambda without capturing, which could convert to pointer to function implicitly. In PrintTheValue, *func, i.e dereference on the pointer results in a reference to function, and for being passed to operator<< of std::cout, it converts to function pointer again, then converts to bool with value true (as a non-null pointer), then you should get the result 1 (or true with the usage of std::boolalpha). If you want to call on func you could func(42) (or (*func)(42)).
A lambda is an unnamed function object of the closure type.
The crucial part for this case, this class does not overload the operator<<.
When you dereference the passed lambda in *func, there is no overload for operator<<, so it converts to nearest acceptable result which is bool (at first it reverts to a regular pointer).
The documentation:
Dereferencing a function pointer yields the lvalue identifying the pointed-to function
int f();
int (*p)() = f; // pointer p is pointing to f
(*p)(); // function f invoked through the function lvalue
// But no sense in *p
It should print 1 (since non-null pointer), which it does for me (g++). The language does allow us to do so, but there's no sense in dereferencing a pointer to function without calling the function. All the peculiarities of the function pointers are due to that they have one reasonable usage, so anything you do with them will support that usage - #Pete Becker
For more on Function Pointers check here, it will aid.
Related
I am trying to cast a lambda function to a function pointer. However, the cast fails when the lambda has a non-void return type. Details see the code snippet.
Is it possible to cast fun2 into a generic function pointer which I can save for later usage?
Update: My intention is to cast all kinds of functions to a "generic function pointer" which can be saved in a std::map. Upon usage, I will cast it back to its original function type.
#include <iostream>
int fun3() { return 1; }
int main(int argc, char *argv[]) {
typedef void (*voidFunctionType)(void);
// Case 1: lambda, return type void
auto fun1 = []() { std::cout << "hello" << std::endl; };
// -> compiles
auto casted_fun1 = (voidFunctionType)fun1;
// Case 2: lambda, return type int
auto fun2 = []() { std::cout << "world" << std::endl; return -1;};
// -> error: invalid cast from type ‘main(int, char**)::<lambda()>’ to type ‘voidFunctionType {aka void (*)()}’
auto casted_fun2 = (voidFunctionType)fun2;
// Case 3: free function, return type int -> compiles
auto casted_fun3 = (voidFunctionType)fun3;
return 0;
}
The problem is that you are using C-style explicit casts. These are notoriously dangerous.
Here in this case the problem is that fun3 (in contrast to fun2) already decays to a function pointer of type int(*)().
You then cast it to void(*)(). This works because the C-style cast will try to do different C++ cast expressions until one works. In particular it will also try a reinterpret_cast.
reinterpret_cast<voidFunctionType>(fun3)
works, because reinterpret_cast can cast any function pointer to any other function pointer.
However, you are not allowed to call the function through the obtained pointer. Doing so causes your program to have undefined behavior. As you can see this cast is of very limited use and dangerous if you are not aware of it.
Don't use C-style casts, use static_cast<voidFunctionType>(fun3) instead and you will get the appropriate compile-time error in both cases.
You cannot use a function (whether free function or lambda) that returns one type as if it returned another (or no) type. Casting the lambda that returns int to void(*)() therefore doesn't make sense.
If you really want to save arbitrary function pointers you can make the lambda cast work by first converting it to a function pointer and then casting it to the destination function pointer type with a reinterpret_cast. I would still not use C style casts, because the reinterpret_cast will at least make it clear what kind of cast you are intending to do:
auto casted_fun2 = reinterpret_cast<voidFunctionType>(+fun2);
The unary + is a common trick to force lambda to function pointer conversion. Note however also that only lambdas without capture can be converted to function pointers.
As I explained above though, you must cast the pointer back to its original type before calling it, so you need to store the type information somewhere. I am not sure how you intend to do that, but you probably need to implement some extended version of std::function, see e.g. this question for how std::function does it.
Will the following work as expected?:
struct A {};
struct B: public A {
int x;
};
void f( B* o ) {
std::cout << o->x << std::endl;
}
int main () {
B b;
b.x = 5;
reinterpret_cast<void(*)(A*)>(f)( &b );
}
Its undefined behaviour to use such pointer after cast:
Any pointer to function can be converted to a pointer to a different function type. Calling the function through a pointer to a different function type is undefined, but converting such pointer back to pointer to the original function type yields the pointer to the original function.
From http://en.cppreference.com/w/cpp/language
So the answer to your question is actually positive - you are allowed to cast but nothing more.
You might ask "what is the point of only casting?" - this is usefull when you want to store various functions in single collection.
See 5.2.10/6 [expr.reinterpret.cast]:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling a function through a pointer to a function type that is not the same as the type used in the definition of the function is undefined.
That said, note as an example that C++ allows you to dereference a null pointer, so maybe allowed is not the right term.
The following command compiles too:
reinterpret_cast<void(*)(A*, int)>(f)( &b, 42 );
It is allowed, as well as the one in the question, no matter if it works as expected or not (it mostly depends on your expectations, as noted by #luk32 in the comments).
The answer to your question would be yes, the cast is allowed, but the invokation of the function through the new pointer leads to an undefined behavior.
I have these two test functions:
int apply_a(int (*fun)(int, int), int m, int n) {
return (*fun)(m,n);
}
int apply_b(int (*fun)(int, int), int m, int n) {
return fun(m,n);
}
they appear to return something different, so why do both of them yield the same result?
int add(int a, int b) {return a + b;}
int res_a = apply_a(add, 2, 3); // returns 5
int res_b = apply_b(add, 2, 3); // returns 5
I would've assumed that one of them would return the pointer address or the pointer itself; rather than the value stored on the pointer...
So why is it doing this?
Because C++ offers syntactic sugar when it comes to handling the address of non-member functions and using pointers to them.
One can get address of such function:
int someFunc(int);
with either:
int (* someFuncPtr)(int) = someFunc;
or:
int (* someFuncPtr)(int) = &someFunc;
There is also syntactic sugar for using such pointer, either call pointed-to function with:
(*someFuncPtr)(5);
or with simplified syntax:
someFuncPtr(5);
(*fun)(m,n) is the same as fun(m,n) due to rules in C and C++ that convert functions to pointers to functions.
In C 2011, the rule is clause 6.3.2.1 4: “A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type “function returning type” is converted to an expression that has type “pointer to function returning type”. In C++, the rule is clause 4.3.
Note that a function designator is not merely an identifier that names a function. It could be an identifier, or it could be another expression. For example, if foo is the name of a function, it is automatically converted to a pointer to a function by the above. Then, since foo is a pointer to the function, *foo is the function. This means you can write:
(*fun)(m,n)
The result is that fun is automatically converted to a pointer, then * evaluates to the function, then *fun is converted back to a pointer, then the function is called. You can continue this and write:
(**************fun)(m,n)
This is the same as fun(m,n). Each * produces the function again, but the compiler automatically converts it back to a pointer. You can continue this battle forever, but the compiler will always win.
In fact, these all have the same effect:
(&fun)(m,n)
( fun)(m,n)
(*fun)(m,n)
It is because you are not returning memory addresses of these values.
Calling a function with pointer does not change it's value it's still calling the function. What you can do is return a value to a variable and then get it's memory address such as:
int result = fun(m,n);
cout << "the result " << result << " pointing at " << &result << endl;
In C and C++ name of functions are also the pointers to the function code. As any pointer you can dereference them using *, which in case of function pointers mean invocation of the function when in addition to dereferencing you use also paranthesis after them, like in your apply_a case. But also valid invocation of C and C++ function is calling them simply by their name, which is apply_b case.
In the code below, function-pointer and what i considered as "function-reference" seems to have identical semantics:
#include <iostream>
using std::cout;
void func(int a) {
cout << "Hello" << a << '\n';
}
void func2(int a) {
cout << "Hi" << a << '\n';
}
int main() {
void (& f_ref)(int) = func;
void (* f_ptr)(int) = func;
// what i expected to be, and is, correct:
f_ref(1);
(*f_ptr)(2);
// what i expected to be, and is not, wrong:
(*f_ref)(4); // i even added more stars here like (****f_ref)(4)
f_ptr(3); // everything just works!
// all 4 statements above works just fine
// the only difference i found, as one would expect:
// f_ref = func2; // ERROR: read-only reference
f_ptr = func2; // works fine!
f_ptr(5);
return 0;
}
I used gcc version 4.7.2 in Fedora/Linux
UPDATE
My questions are:
Why function pointer does not require dereferencing?
Why dereferencing a function reference doesn't result in an error?
Is(Are) there any situation(s) where I must use one over the other?
Why f_ptr = &func; works? Since func should be decayed into a pointer?
While f_ptr = &&func; doesn't work (implicit conversion from void *)
Functions and function references (i.e. id-expressions of those types) decay into function pointers almost immediately, so the expressions func and f_ref actually become function pointers in your case. You can also call (***func)(5) and (******f_ref)(6) if you like.
It may be preferable to use function references in cases where you want the &-operator to work as though it had been applied to the function itself, e.g. &func is the same as &f_ref, but &f_ptr is something else.
"Why function pointer does not require dereferencing?"
Because the function identifier itself is actually a pointer to the function already:
4.3 Function-to-pointer conversion
§1 An lvalue of function type T can be converted to an rvalue of type “pointer to T.” The result is a pointer to the function.
"Why dereferencing a function reference doesn't result in an error?"
Basically you can look at defining a reference as defining an alias (alternative name). Even in the standard in 8.3.2 References in part addressing creating a reference to an object, you will find:
"a reference can be thought of as a name of an object."
So when you define a reference:
void (& f_ref)(int) = func;
it gives you the ability to use f_ref almost everywhere where it would be possible to use func, which is the reason why:
f_ref(1);
(*f_ref)(4);
works exactly the same way as using the func directly:
func(1);
(*func)(4);
See here.
The address-of operator acts like you would expect, as it points to a function but cannot be assigned. Functions are converted to function pointers when used as rvalues, which means you can dereference a function pointer any number of times and get the same function pointer back.
As there are good answers from other people here, there is no answer explaining why f_ptr = &&func; does not work. When you apply the addressof operator & to a variable/function, you get its address. The adress itself is an r-value/a temporary variable. You cannot take the address of a temporary.
But it seems that there is a type error. The message implicit conversion from void* is very compiler specific for this code. I guess you are using GCC/Clang. GCC/Clang offers the ability to take the address of labels like &&label. The resulting value is of type void*. Other compilers will output something like cannot take address of temporary or invalid syntax. When using these compilers this kind of error could have been hidden without any warning in special circumstances:
int main() {
int foo = 42;
foo:;
void* a = &foo; // take the address of a variable/function
void* b = &&foo; // take the address of a label
std::cout << *(int*)a << '\n';
goto *b;
};
But who would name everything the same?
Does dereferencing a pointer and passing that to a function which takes its argument by reference create a copy of the object?
In this case the value at the pointer is copied (though this is not necessarily the case as the optimiser may optimise it out).
int val = *pPtr;
In this case however no copy will take place:
int& rVal = *pPtr;
The reason no copy takes place is because a reference is not a machine code level construct. It is a higher level construct and thus is something the compiler uses internally rather than generating specific code for it.
The same, obviously, goes for function parameters.
In the simple case, no. There are more complicated cases, though:
void foo(float const& arg);
int * p = new int(7);
foo(*p);
Here, a temporary object is created, because the type of the dereferenced pointer (int) does not match the base type of the function parameter (float). A conversion sequence exists, and the converted temporary can be bound to arg since that's a const reference.
Hopefully it does not : it would if the called function takes its argument by value.
Furthermore, that's the expected behavior of a reference :
void inc(int &i) { ++i; }
int main()
{
int i = 0;
int *j = &i;
inc(*j);
std::cout << i << std::endl;
}
This code is expected to print 1 because inc takes its argument by reference. Had a copy been made upon inc call, the code would print 0.
No. A reference is more or less just like a pointer with different notation and the restriction that there is no null reference. But like a pointer it contains just the address of an object.