value of function in c/C++ [duplicate] - c++

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How does dereferencing of a function pointer happen?
If we have
void f() {
printf("called");
}
Then the following code will result in output of "calledcalled":
f();
(*f)();
I don't really understand how this works…what is the difference between *f and f? And why would you call a function using the latter syntax?

There are two ways to call a function in C++:
By name:
f();
Through a function pointer:
typedef void (*fptr_t)();
fptr_t fptr = &f;
(*fptr)();
Now, using the address-of operator on a function name (&f) obviously creates a function pointer. But the function name can implicitly convert to a function pointer when certain conditions are met. So the above code could be written as:
typedef void (*fptr_t)();
fptr_t fptr = f; // no address-of operator, implicit conversion
(*fptr)();
Your second example is doing exactly this, but using a temporary variable to hold the function pointer instead of a named local variable.
I prefer to use address-of when creating function pointers, the meaning is much clearer.
A related note: The function call operator will automatically dereference a function pointer if one is provided. So this also is legal:
typedef void (*fptr_t)();
fptr_t fptr = &f;
fptr();
That's pretty useful with templates, because the same syntax works whether you have a function pointer or a functor (object implementing operator()) passed in.
And neither shortcut works with pointer-to-members, there you NEED explicit address-of and dereference operators.
In C, #Mehrdad explains that all function calls use a function pointer.

The first one is somewhat of a syntactic sugar for the second one. The second one makes it obvious that you're making the call through a pointer, and it's used mainly with function pointers rather than regular functions, to make the distinction more obvious.

Just as an array type is almost entirely equivalent to the corresponding pointer-to-element type, a function type is entirely equivalent to the corresponding pointer-to-function type:
void (*func1)() = f; // function type -> pointer-to-function type
void (*func2)() = &f; // pointer-to-function type -> pointer-to-function type
and also
void (*func)() = ...;
func(); // pointer-to-function type + function-call operator
(*func)(); // function type + function-call operator
So, in
(*f)();
you're dereferencing f (implicitly converted to &f), and then apply the function-call operator.

Related

C++ function pointer at declaration and argument

I am confused about using C++ function pointers.
using fn_p1 = void(int); // function pointer
using fn_p2 = void (*)(int);
void functional(fn_p1 f) {
f(1);
}
void callback(int value){
// do something
}
int main() {
fn_p2 f = callback; //works
fn_p1 f1 = static_cast<fn_p1>(f); //does not work
fn_p1 f2 = callback; //does not work
fn_p1 f2 = static_cast<fn_p1>(callback); //does not work
functional(f); // works, the argument is form of void(*)(int)
f(1); // works
functional(*f); // works, the argument is dereferenced, void(int)
(*f)(1); // works
return 0;
}
I know there is no difference if you call a function pointer with f(1), (*f)(1), or (*****f)(1).
I don't get how functional(f); works but fn_p1 f1 = static_cast<fn_p1>(f); and its variants can not since they define the function pointer as using fn_p1 = void(int);.
Could anyone explain how the function pointer works or how the compiler deals with it?
The most useful error that the IDE should give you is on the line fn_p1 f2 = callback;:
Illegal initializer (only variables can be initialized) [illegal_initializer]
(This is the message I get from clangd.)
That means literally that an entity of type void(int) (or more in general someReturnType(someArgTypes...)) is not a variable.
Indeed, in C++ functions are not first class, which means that you can't pass them to function and don't get them in return from function; when you think you are successfully doing so, you're in reality passing or taking back function pointers.
In other words there's no such a thing in C++ as "a function value". Functions are not values that you can assign to.
When you write
fn_p1 f2 = callback; // assuming using fn_p1 = void(int);
you are truly trying to create a variable of type void(int). But such a thing doesn't exist, hence the error.
The static_casts don't work for fundamentally the same reason.
As regards
void functional(fn_p1 f) {
f(1);
}
function-to-(function)pointer decaying is happening. f is truly of type fn_p1*.
You can easily verify it by writing an invalid statement in functional in order to trigger a compiler error telling you what the type of f is, like this
void functional(fn_p1 f) {
int foo = f;
f(1);
}
Clangd answers this
Cannot initialize a variable of type 'int' with an lvalue of type 'fn_p1 *' (aka 'void (*)(int)') [init_conversion_failed]
which indirectly tells you that f is of type fn_p1*, so you better write that instead of fn_p1 as the type of the parameter of functional, at least for clarity (similarly to how you should prefer writing T* instead of T[] as a parameter type in a function taking a c-style array of Ts).
If you truly want to assign functions to variables, you should look at lambdas, structs+operator(), std::function, and the topic of function objects in general.

What difference between void(void) and void(*)(void)?

void(*)(void) is a function pointer while I suppose void(void) is also a way to represent function type. It is used as template parameter in std::function <functional>
What is void(void) and how it is different from void(*)(void)?
What is void(void) and how it is different from void(*)(void)?
They are distinct types. Although the former(void(void)) can be implicitly converted to the latter(void(*)(void)) in many contexts.
The type void(void) is called a function type. The following are also function types:
int (int, int) //this is a function type
void(int) //this is a function type as well
On the other hand, void (*)(void) is a pointer to a function type. That is, it is a pointer that points to a function with 0 parameters and return type of void.
TL;DR
The void(void) is a specification of a function type, it's
signature.
The void(*)(void) is a pointer to function.
These are distinct.
First, let's start by saying, that sometimes the void(void) will be automatically treated as a pointer to function (i.e. in a parameter list). We still can be explicit and use the void(*)(void), but the void(void) will be an equivalent in these cases.
// Here, we explicitly state that the f is a pointer to function
void foo(void (*f)(void), int i);
// Equivalent, f is automatically treated as a pointer to the function
void foo(void f(void), int i);
This will not be the case for the mentioned std::function for example. The types of the two are different, yet may have similar behavior (i.e. we can use the function call operator on a pointer to function).
void bar();
// Prints 1
std::cout << std::is_same<void(void), decltype(bar)>::value << '\n';
// Prints 1 as well
// Note the pointer type specifier
std::cout << std::is_same<void(*)(void), decltype(bar)*>::value << '\n';
// Prints 0
// Note the absence of the pointer type specifier
std::cout << std::is_same<void(*)(void), decltype(bar)>::value << '\n';
And particularly:
// Ok
std::function<decltype(bar)> fn1 = bar;
// error: variable ‘std::function<void (*)()> fn2’ has initializer but incomplete type
std::function<decltype(bar)*> fn2 = bar;
Note, that we can however "store" a pointer to a member function in std::function, but even then the template's parameter still won't be of a pointer to function type, but a plain function signature.
struct MyType {
void func(int) {}
};
int main() {
// Note, we can't have a member function without an instance of the type
// Thus we specify the usually implicit first param and the explicit int param
std::function<void(MyType&, int)> fn_mem = &MyType::func;
MyType my_object;
fn_mem(my_object, 21);
}
For more on std::function please refer to the reference. In short, the use of the std::function instead of the function pointers has the same moto as using the smart pointers instead of the raw pointers.
You may wonder on other uses of the void(void) or int(int) style function type specifications, so here's another example you may see often:
using func_t = int(int);
// func_ptr_func return a pointer to the func_t type alias
func_t* func_ptr_func();
N.B. unlike in the case of a parameter, the compiler won't treat the function type in a return as a pointer to function type. Thus, we must explicitly specify the pointer type in case of the return.
// Here, baz is a function that doesn't take any agruments
// And returns a pointer to a function that takes an int argument and "returns" void
void (*baz())(int);
for void fun(){}, std::is_same_v<void(void)>, decltype(fun)> is true; and std::is_same_v<void(*)(void)>, decltype(&fun)> is true. In fact, those are their real types. However, the standard approve you convert an object that has type void(void) to void(*)(void) implicitly (so you can even write (******funptr)()), that's why we always confuse them.

C++ function pointers, again. Confusion regarding syntax

On this page I found a good example of function pointers in C++ (as well as of functors, but this question isn't about functors). Below is some copypasta from that page.
#include <iostream>
double add(double left, double right) {
return left + right;
}
double multiply(double left, double right) {
return left * right;
}
double binary_op(double left, double right, double (*f)(double, double)) {
return (*f)(left, right);
}
int main( ) {
double a = 5.0;
double b = 10.0;
std::cout << "Add: " << binary_op(a, b, add) << std::endl;
std::cout << "Multiply: " << binary_op(a, b, multiply) << std::endl;
return 0;
}
I understand the code in general terms, but there are a couple of things that I've always found confusing. Function binary_op() takes a function pointer *f, but when it's used, for example on line 19 binary_op(a, b, add), the function symbol add is passed in, not what one would think of as its pointer, &add. Now you may say that this is because the symbol add is a pointer; it's the address of the bit of code corresponding to the function add(). Very well, but then there still seems to be a type discrepancy here. The function binary_op() takes *f, which means f is a pointer to something. I pass in add, which itself is a pointer to code. (Right?) So then f is assigned the value of add, which makes f a pointer to code, which means that f is a function just like add, which means that f should be called like f(left, right), exactly how add should be called, but on line 12, it's called like (*f)(left, right), which doesn't seem right to me because it would be like writing (*add)(left, right), and *add isn't the function, it's the first character of the code that add points to. (Right?)
I know that replacing the original definition of binary_op() with the following also works.
double binary_op(double left, double right, double f(double, double)) {
return f(left, right);
}
And in fact, this makes much more sense to me, but the original syntax doesn't make sense as I explained above.
So, why is it syntactically correct to use (*f) instead of just f? If the symbol func is itself a pointer, then what precisely does the phrase "function pointer" or "pointer to a function" mean? As the original code currently stands, when we write double (*f)(double, double), what kind of thing is f then? A pointer to a pointer (because (*f) is itself a pointer to a bit of code)? Is the symbol add the same sort of thing as (*f), or the same sort of thing as f?
Now, if the answer to all of this is "Yeah C++ syntax is weird, just memorise function pointer syntax and don't question it.", then I'll reluctantly accept it, but I would really like a proper explanation of what I'm thinking wrong here.
I've read this question and I think I understand that, but haven't found it helpful in addressing my confusion. I've also read this question, which also didn't help because it doesn't directly address my type discrepancy problem. I could keep reading the sea of information on the internet to find my answer but hey, that's what Stack Overflow is for right?
This is because C function pointer are special.
First of, the expression add will decay into a pointer. Just like reference to array will decay into a pointer, reference to function will decay into a pointer to function.
Then, the weird stuff it there:
return (*f)(left, right);
So, why is it syntactically correct to use (*f) instead of just f?
Both are valid, you can rewrite the code like this:
return f(left, right);
This is because the dereference operator will return the reference to the function, and both a reference to a function or a function pointer are considered callable.
The funny thing is that a function reference decay so easily that it will decay back into a pointer when calling the dereference operator, allowing to dereference the function as many time as you want:
return (*******f)(left, right); // ah! still works
As the original code currently stands, when we write double (*f)(double, double), what kind of thing is f then?
The type of f is double (*)(double, double) i.e. it is a pointer to a function of type double(double,double).
because (*f) is itself a pointer
It is not.
Q: What do you get when you indirect through a pointer (such as in *f)? A: You get an lvalue reference. For example, given an object pointer int* ptr, the type of the expression *ptr is int& i.e. lvalue reference to int.
The same is true for function pointers: When you indirect through a function pointer, you get an lvalue reference to the pointed function. In the case of *f, the type is double (&)(double, double) i.e. reference to function of type double(double,double).
Is the symbol add the same sort of thing as (*f), or the same sort of thing as f?
The unqualified id expression add is the same sort of thing as *f i.e. it is an lvalue:
Standard draft [expr.prim.id.unqual]
... The expression is an lvalue if the entity is a function ...
the function symbol add is passed in, not what one would think of as its pointer, &add. Now you may say that this is because the symbol add is a pointer;
No. That's not the reason.
add is not a pointer. It is an lvalue. But lvalues of function type implicitly convert to a pointer (this is called decaying):
Standard draft [conv.func]
An lvalue of function type T can be converted to a prvalue of type “pointer to T”. The result is a pointer to the function.
As such, the following are semantically equivalent:
binary_op(a, b, add); // implicit function-to-pointer conversion
binary_op(a, b, &add); // explicit use of addressof operator
So, why is it syntactically correct to use (*f) instead of just f?
Turns out that calling a function lvalue has the same syntax as calling a function pointer:
Standard draft [expr.call]
A function call is a postfix expression followed by parentheses containing a possibly empty, comma-separated list of initializer-clauses which constitute the arguments to the function.
The postfix expression shall have function type or function pointer type.
For a call to a non-member function or to a static member function, the postfix expression shall either be an lvalue that refers to a function (in which case the function-to-pointer standard conversion ([conv.func]) is suppressed on the postfix expression), or have function pointer type.
These are all the same function call:
add(parameter_list); // lvalue
(*f)(parameter_list); // lvalue
(&add)(parameter_list); // pointer
f(parameter_list); // pointer
P.S. These two declarations are equivalent:
double binary_op(double, double, double (*)(double, double))
double binary_op(double, double, double (double, double))
This is because of the following rule, which is complementary to the implicit decay into function pointer:
Standard draft [dcl.fct]
The type of a function is determined using the following rules.
The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator.
After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T” ...
First of all a function parameter specified as a function declaration is adjusted to pointer to the function when the compiler determinates the type of the parameter. So for example following function declarations
void f( void h() );
void f( void ( *h )() );
are equivalent and declare the same one function.
Consider the following demonstrative program
#include <iostream>
void f( void h() );
void f( void ( *h )() );
void h() { std::cout << "Hello Ray\n"; }
void f( void h() ) { h(); }
int main()
{
f( h );
}
From the c++ 17 Standard (11.3.5 Functions):
5 The type of a function is determined using the following rules. The
type of each parameter (including function parameter packs) is
determined from its own decl-specifier-seq and declarator. After
determining the type of each parameter, any parameter of type “array
of T” or of function type T is adjusted to be “pointer to T”.
On the other hand, according to the C++ 17 Standard
9 When there is no parameter for a given argument, the argument is
passed in such a way that the receiving function can obtain the value
of the argument by invoking va_arg (21.11). [ Note: This paragraph
does not apply to arguments passed to a function parameter pack.
Function parameter packs are expanded during template instantiation
(17.6.3), thus each such argument has a corresponding parameter when a
function template specialization is actually called. — end note ] The
lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3)
standard conversions are performed on the argument expression
So what is the difference between these two declarations
void f( void h() );
void f( void ( *h )() );
For the first declaration you may consider the parameter h within the function body like a typedef for a function pointer.
typedef void ( *H )();
For example
#include <iostream>
void f( void h() );
void f( void ( *h )() );
void h() { std::cout << "Hello Ray\n"; }
typedef void ( *H )();
void f( H h ) { h(); }
int main()
{
f( h );
}
According to the C++ 17 Standard (8.5.1.2 Function call)
1 A function call is a postfix expression followed by parentheses
containing a possibly empty, comma-separated list of
initializer-clauses which constitute the arguments to the function.
The postfix expression shall have function type or function pointer
type.
So you may also define the function like
void f( void h() ) { ( *h )(); }
Or even like
void f( void h() ) { ( ******h )(); }
because when the operator * is applied to a function name then the function name is implicitly convereted to pijnter to the function.

What is the difference between &foo::function and foo::function?

I am using the gtkmm library on linux to draw a simple menu for my GUI.
In the below code the compiler complained about unable to resolve address
sigc::mem_fun(*this, AppWindow::hide)));
^
appwindow.cpp:15:41: note: could not resolve address from overloaded function
But when I insert the & it compiles fine
m_menu_app.items().push_back(MenuElem("Quit",
sigc::mem_fun(*this, &AppWindow::hide)));
What difference does it make here? Isn't the hide function just an address in the first place?
This is the exact definition of the function-to-pointer conversion, [conv.func]:
An lvalue of function type T can be converted to a prvalue of type
“pointer to T.” The result is a pointer to the function.55
55) This conversion never applies to non-static member functions because an lvalue that refers to a non-static member function
cannot be obtained.
Thus the decay that we see with normal, non-member functions1 doesn't apply and you need to explicitly take the address.
I.e.
void f();
struct A {
void f();
static void g();
};
auto a = f; // Ok: auto deduced as void(*)()
auto b = A::f; // Error: A::f not an lvalue, auto cannot be deduced
auto c = A::g; // Ok: auto deduced as void(*)()
1 Or static member functions.
For global (non-member) functions, the name of the function evaluates to the address of that function except when passed to the & operator, so you can (for example) assign to a pointer to a function either with or without the & equivalently:
int f() {}
int (*pf1)() = f;
int (*pf2)() = &f;
So, in this case there's really no difference between the two.
For member functions1, however, the rules are a bit different. In this case, the & is required; if you attempt to omit the &, the code simply won't compile (assuming a properly functioning compiler, anyway).
There's no particular reason this would have to be the case--it's just how Bjarne decided things should be. If he'd decided he wanted the name of a member function to evaluate to a pointer to a member (equivalent to how things work for non-member functions) he could have done that.
1. Other than static member functions, which mostly act like non-member functions.
When a function is a non-static member function of a class, then it is necessary to use the form &ClassName::functionName when a pointer to the member function is expected in an expression.
When a function is a static member function of a class, both ClassName::functionName and &ClassName;:functionName can be used when a pointer to a function is expected in an expression.
When a function is a global, i.e. non-member, function, both functionName and &functionName can be used when a pointer to a function is expected in an expression.

Syntax of C++ templates with function type parameters

I'm used to seeing syntax like this for function pointers
int (*pointer_name) (float, char *);
void call_function (void (*)(int), int);
In some C++03 functional libraries I see types used this way:
abc::function<void(*)(int,float)> f;
In C++11's std::function I see the type given this way
std::function<void(int,float)> f;
There is a missing (*). Why?
The C++03 function<T> has T being an identical type to the corresponding function pointer. It's easy to imagine the implementation.
std::function in C++11 is supported by core language enhancements. Have template argument types been extended to accomodate callability?
std::function (and its inspiration, boost::function) does not only store function pointers. It can also store function objects. In that sense, passing a function signature as a template parameter is similar to how a smart pointer usually take the type of the pointee as a template parameter, not a pointer type!
Contrast:
int* p; // indirection to an object of type int
std::unique_ptr<int> q; // indirection to an object of type int
with
typedef void signature_type(); // a function type
// indirection to something callable with signature_type as a signature
// i.e. f() has type void
// only work for freestanding functions however
signature_type* f;
// indirection to something callable with signature_type as a signature
// i.e. g() has type void
// not restricted to function pointers!
std::function<signature_type> g;
This is a useful convention.
There is nothing magic here, the type
void(int,float)
is the type of a function without the names. It matches a function like void g(int x, float y).
With templates you don't have to use function pointers, you can use function types as well.
As with other elements, functions have a type, and you can use either the type or the pointer to the type in different contexts. The missing (*) you are expecting is just the pointer-to syntax.
int (*pointer_name) (float, char *);
typedef int my_function_type(float,char*);
my_function_type * pointer_name2;
The types of pointer_name and pointer_name2 are the same: pointer to a function that returns int and takes two arguments of types float and char*. Note that this is exactly equivalent to other types like int, with the difference that you cannot declare a variable to be of type function, only pointer to function.
The interface of std::function (or boost::function) just takes the signature of the function. The type argument is not a pointer to function but rather the type of a function (like my_function_type in the code above)
Function types aren't new in C++11 (see 8.3.5 in C++98). IIRC, the improvement over what TR1 and boost provide for function are quite minor.