What does the following syntax mean?
set<element*, bool (*) (element *, element *)> * getNumbers();
I'm not familiar with the (*) part. Any explanation would be great. Thanks
Here it means that the second template parameter is a function pointer:
bool (*) (element *, element *)
is "pointer to a function that takes two element*s and returns bool".
You may also see (*) in connection with pointers to arrays;
int (*) [32]
is the type "pointer to an array of 32 ints".
It is a function pointer, more precisely bool (*) (element *, element *) is the type of a function pointer. In this case its a function that takes two element pointers and returns a bool.
Its makes more sense when you see it used as function parameter, then it will have a name after the first *. For example bool (*fun) (element *, element *).
It's a function pointer. You can read about it further here, for example:
http://www.cprogramming.com/tutorial/function-pointers.html
bool (*) (element *, element *) names the type of a pointer to function, where the function takes two element* pointers as parameters and returns a bool.
Second template argument is function pointer, designed to compare 2 element*. If you put such function pointer in constructor of std::set - you will be able to create set of elements with custom compare function (or without overloaded operator<).
Related
As I starting to learn C++, this question may be stupid but I do not understand some strange pointers.
void (*p1(int*))(float*);
int* (*(*p2)(double(*fp1)(char), int*))(float *);
int* (*(*p3)(double(*)(char), int*))(double*);
I think p2 and p3 are function pointers pointing to a function that returns a pointer to int but I am totally lost about the rest.
Also I don't understand p1 at all.
Can anyone help me please?
Thanks.
Because of p1(int*) we know that p1 is a function taking argument int*. The return type of the function is the rest of the declaration once we delete the part we already analyzed, void (*)(float*) (i.e. pointer to function taking float * and returning void.
p2 and p3 have the same form, just p2 gives a name to the function parameter. So I will only address one of them, p3.
Because of (*p3)(double(*)(char), int *) we know that (*p3) is a function taking arguments double(*)(char) and int *. The return type of the function is the rest of the declaration without the part we already analyzed, i.e. int*(*)(double *). Since (*p3) has that function type, then p3's type is: pointer to that function.
p1 is a function that returns a pointer to a function. You are correct about p2. It is a pointer to a function that takes two arguments - a pointer to a function and a pointer to an int - and returns a pointer to a function. p3 is the same.
Consider the code:
void foo(char a[]){
a++; // works fine, gets compiled
//...
}
Now, consider this:
void foo(){
char a[50];
a++; // Compiler error
//...
}
I heard an array is equivalent to a constant pointer and can't be incremented as it is not a lvalue...
Then why does first code gets compiled, is it so because array arguments to functions are passed as a pointer, i.e. T[] is converted to T* for passing..
So, foo(a) passes a as a pointer.
But is it not back converted to T[] again because is declared as:
void foo(char a[]);
When you pass an array as an argument to a function, it decays to a pointer.
So the thing you increment inside the function body is a pointer, not an array.
This is a rather unfortunate feature inherited from the C language, with the rather yucky name of "decay." Since C once did not allow passing compound types by value, they decided to allow programmers to specify arrays as function parameter types, but only cosmetically. The array type decays to a pointer type, implementing a sort of pass-by-reference semantic different from the rest of the language. Ugly.
To recap (and others have already said this), the signature
void foo(char a[]); // asking for trouble
is unceremoniously mangled into
void foo(char *a);
… all for the sake of compatibility with ancient C code. Since you aren't writing ancient C code, you should not make use of this "feature."
However, you can cleanly pass a reference to an array. C++ requires that the size of the array be known:
void foo( char (&a)[ 50 ] );
Now a cannot be modified within the function (edit: its contents can, of course — you know what I mean), and only arrays of the right size may be passed. For everything else, pass a pointer or a higher-level type.
I heard an array is equivalent to a constant pointer
You can think of it that way, but they're not equivalent.
An array decays to a pointer when passed to a function, that's why inside the function it's valid.
Just because the signature is void foo(char a[]) doesn't make a an array.
Outside the function, it's just an array, and you can't do pointer arithmetics on it.
In C++, any function parameter of type "array of T" is adjusted to be "pointer to T". Try this code:
void foo(char a[]) {}
void foo(char* a) {} //error: redefinition
They are indeed the same function.
So, why can we pass an array argument to a function as a pointer parameter? Not because an array is equivalent to a constant pointer, but because an array type can be implicitly converted to an rvalue of pointer type. Also note the result of the conversion is an rvalue, that's why you can't apply the operator ++ to an array, you can only apply this operator to an lvalue.
I heard an array is equivalent to a constant pointer and can't be incremented as it is not a lvalue...
Almost.
An array expression is a non-modifiable lvalue; it may not be an operand to operators such as ++ or --, and it may not be the target of an assignment expression. This is not the same thing as a constant pointer (that is, a pointer declared as T * const).
An array expression will be replaced with a pointer expression whose value is the address of the first element of the array except when the array expression is an operand of the sizeof or unary & operators, or when the array expression is a string literal being used to initialize another array in a declaration.
When you call a function with an array argument, such as
int a[N];
...
foo(a);
the expression a is converted from type "N-element array of int" to "pointer to int" and this pointer value is what gets passed to foo; thus, the corresponding function prototype should be
void foo (int *arr) {...}
Note that in the context of a function parameter declaration, T a[] and T a[N] are identical to T *a; in all three cases, a is declared as a pointer to T. Within the function foo, the parameter arr is a pointer expression, which is a modifiable lvalue, and as such it may be assigned to and may be the operand of the ++ and -- operators.
Remember that all these conversions are on the array expression; that is, the array identifier or other expression that refers to the array object in memory. The array object (the chunk of memory holding the array values) is not converted.
When you pass an array a[] to a function, it passes the value of 'a', an address, into the function. so you can use it as a pointer in the function. If you declare an array in the function, 'a' is constant because you can't change its address in memory.
#include<iostream>
using namespace std;
void passPointer(int *pointer)
{
cout << *pointer;
}
int main()
{
int *iNum = new int(25);
passPointer(iNum);
return 0;
}
Can someone explain to me why when I use the passPointer() function in main, it has to be passPointer(iNum) but not passPointer(*iNum)? Is it because I am dereferencing it at the parameter if I use *? Please explain as detailed as you can as I am a bit confused.
Thanks guys.
It is because you have declared passPointer to take an argument of
type int*. iNum has type int*, and so can be passed directly to
passPointer. *iNum has type int, and there is no implicit
conversion of int to int*, so you can't pass it to passPointer.
More generally, in C++ (and in just about all other typed languages as
well), every expression and every variable has a type. The type of an
expression is expressed in terms of the type of its operands: if the
type of the operand of a unary * is T* (and the type must be a
pointer), then the type of the results is T. And to call a function,
you must provide the right number of arguments, with the right types.
I am very sympathetic to these sorts of questions, because this is one of the only things that I had trouble with when learning C++.
The basic problem is that in the syntax of C++, the * and & characters are used for many different things with similar but subtly different meanings.
In your case, you are considering using * in four different places.
In the first place: int *iNum = new int(25);, the * is sitting in a declaration. This means that is is a type annotation saying that iNum is a pointer.
In the second place: passPointer(*iNum);, the * is sitting in an expression. This means that it is the dereference operator, which means: "get the value pointed to by iNum". In this case the value pointed to by iNum is an int. As you will see later, passPointer is declared to take an argument of type pointer to int, so you cannot pass a plain int as an argument to passPointer. You should instead just pass iNum (as iNum is a pointer to int).
In the third place: void passPointer(int *pointer), the * is again sitting in a declaration. This means that it has the same meaning as in the first place - it says that pointer is a pointer (to int).
In the fourth place: cout << *pointer;, the * is again sitting in an expression. This means that, as in the second case, it is saying "dereference pointer and get the value that pointer is storing the address of".
This creates variable of name iNum and type int *:
int *iNum = new int(25);
This accept parameter of type int *:
void passPointer(int *pointer)
This passes the parameter of name iNum and type int *:
passPointer(iNum);
No need to think of pointers, these are all data types. Think of pointers only when you do pointer arithmetics and referencing, referencing. ;)
int**** is just a type.
Is it because I am dereferencing it at the parameter if I use *?
Yes. iNum has type pointer to int, *iNum has type int. If you had a function that takes an int, then you could pass it *iNum.
The passPointer() function takes a pointer-to-int. iNum is already a pointer-to-int, so you just pass it as-is. There is no need to deference it.
what does "T const *[]" as parameter
type mean?
What's the difference
compared to "T *[]"?
And as last
question: why can't I pass a "T *[]"
to a function that requires a "T
const * []" as parameter?
Thank you for your help.
Tobias
As a type in general, it's an array of pointers to a constant T.
Try putting a name in it:
T const *x[];
and apply the usual rules: [] binds tighter than *, so it's an
array. Then the * means that its an array of pointers, and
finally, they all point to a constant T. (As usual, const
modifies whatever is to the left of it.)
As a parameter, of course, an array type is converted to
a pointer type, so we end up with a pointer to a pointer to
a constant T. This could also be written:
T const **
If you drop the const, you end up with:
T **
which is not the same thing as T const**.
And the reason you can't pass a T** or a T*[] to the first
form is to prevent things like:
void f(int const* p1[]; int const* p2)
{
p1[0] = *p2;
}
int const x = 10;
int* px[1];
f(px, &x);
*px[0] = 20; // Where does this write?
The fact that the declarations are written using [] is, in this
case, misleading, since the rules for pointers to pointers still
apply.
It's an array of pointers to constant objects of type T (i.e. the pointer can change, but you cannot call a non-const function, or modify a non-mutable data member on these objects). T *[] is an array of pointers to non-const ojects. You can't pass T *[] to a function requiring a T const *[] as it would invalidate the const correctness of the pointers.
See here for more information.
what do you mean by following line ?
void(*fnctn)(void(*)(int *,void **),int(*)(void**,int*));
What you have essentially is a function pointer 'fnctn' which takes two function pointers for its two parameters. If we break this down bit by bit, what you have is the following:
The first parameter void(*)(int*, void**) is a function pointer returning void and taking an int* and void** as it's two parameters.
The second parameter int(*)(void**, int*) is a function pointer returning an int value and taking a void** and an int* as its two parameters.
Maybe it's clearer to see as follows:
typedef void(*param1)(int *, void**);
typedef int(*param2)(void**, int*);
typedef void(*fnctn)(param1, param2);
$ cdecl
Type `help' or `?' for help
cdecl> explain void(*fnctn)(void(*)(int *,void **),int(*)(void**,int*));
declare fnctn as pointer to function (pointer to function (pointer to int, pointer to pointer to void) returning void, pointer to function (pointer to pointer to void, pointer to int) returning int) returning void
cdecl>
Wow, well, a typedef or two would be nice here, but it says...
declare a pointer to a function that returns void with the identifier "fnctn" that takes as parameters a function that returns void and takes an int* and a void** as parameters as well as a function that returns an int which takes a void** and an int* as parameters.
Further reading: Function pointer syntax
Try learning the clockwise spiral rule: http://c-faq.com/decl/spiral.anderson.html With this, you can learn what just about any function declaration will mean, thus enabling you to determine what it does.
Looks to me like declaration of a function pointer to a function that takes a function pointer to a function that takes int*, void** as arguments and returns void as the first parameter, and a function pointer to a function that takes void**, int* as arguments and returns int as the second parameter. This function is of return type void.
Clear as mud.