Reputation: 556
Before saying it would be a duplicate question and downvote (as it happened before), I searched and found nothing alike.
I, like many others, am trying to learn the uses of C++ reference variables and to relate them to pointers. I found it easier to make a table and I need to know whether it needs to be amended.
int *n int n int &n caller/local
void foo(int *n) n &n &n caller
void foo(int n) *n n n local
void foo(int &n) *n n n caller
The table wants to reflect all legal passed parameters.
[1,1]: passing by reference (trivial)
[1,2]: passing by reference
[1,3(1)]: passing by reference, an is an address(?)
[1,3(2)]: passing by reference, as n is used as alias(?)
[2,1]: passing by value, as dereferencing
[2,2]: passing by value (trivial)
[2,3(1)]: passing by value, using value of n (where n is an alias)
[2,3(2)]: passing by value (dereferencing n, which is an address)
[3,1(1)]: passing by reference, as foo accepts address
[3,1(2)]: passing by reference, reference of value at address n
[3,2(1)]: passing by reference (trivial)
[3,2(2)]: passing by reference, as foo accepts address or reference
[3,3]: passing by reference (trivial, as argument matches parameter exactly)
Upvotes: 4
Views: 219
Reputation: 106254
Maybe I'm interpreting your table wrong, but assuming you're inside the three functions on the left, and want to get an int*
to n
, use n
, and bind a reference to the int
value accessed via n
respectively:
Your original table
int *n int n int &n
void foo(int *n) n &n n/&n
void foo(int n) *n n n/*n
void foo(int &n) n/*n n/&n n
Given the function signatures on the left, you have the following mistakes:
In foo(int* n)
:
int
you want *n
not &n
int&
s to *n
In foo(int n)
n
you want &n
not *n
int&
to n
you want n
, not *n
n
is a local, copied and different from the caller's n
In foo(int& n)
:
n
you want &n
not n
or *n
n
you just want n
not/never &n
So, I'd write the table like this (I've appended columns for address of n
and whether n
is the n
from the calling context or a local copy)
Suggested corrected table
int* int int& n2 = ... int* p = ... caller/local
void foo(int* p_n) p_n *p_n *p_n p_n caller
void foo(int n) &n n n &n local
void foo(int& n) &n n n &n caller
I'm not convinced such a table has much utility in clarifying the role of references and pointers though.
UPDATE: your comment explains you wanted the table to communicate the "passing form", which I take to be the code you'd need inside the caller of foo
. The correct table for that should be:
int *n int n int &n caller/local
void foo(int *n) n &n &n caller
void foo(int n) *n n n local
void foo(int &n) *n n n caller
Upvotes: 1
Reputation: 409482
A function
void foo(int& n);
does not accept an address (a pointer), and not literals either.
So you can't call it like
int a = ...;
foo(&a); // Trying to pass a pointer to a function not taking a pointer
or
foo(1); // Passing R-value is not allowed, you can't have a reference to a literal value
There is an exception though, if you have a constant reference, like
int foo(const int& n);
then literal values are allowed, because then the referenced value can't be changed.
Likewise for
void foo(int* n);
you must pass a pointer.
So for example:
int a = ...;
int& ra = a; // ra references a
foo(&a); // OK
foo(&ra); // OK
foo(a); // Fail, a is not a pointer
foo(ra); // Fail, ra is not a pointer
foo(1); // Fail, the literal 1 is not a pointer
And for the last:
void foo(int n);
With examples:
int a = ...;
int& ra = a; // ra references a
int* pa = &a; // pa points to a
foo(a); // OK, the value of a is copied
foo(ra); // OK, the value of the referenced variable is copied
foo(*pa); // OK, dereferences the pointer, and the value is copied
foo(pa); // Fail, passing a pointer to a function not expecting a pointer
foo(1); // OK, the literal value 1 is copied
Upvotes: 5
Reputation: 76308
operator*
and operator&
Both operator&
(unary) and operator*
(unary) can be overloaded.
This means that if n
is a class type type
, then *n
can literally have any form including, but not limited to type*
, type&
, type
.
An example (stupid, but still a valid example) would be:
struct type {
int x;
};
int& operator&(type& t) {
return t.x;
}
You can also have infinite number of pointer indirections. In which case *n
, **n
, ***n
might also yield Type*
as well as Type&
.
As an example, given two functions:
void func_ptr(int*) {}
void func_ref(int&) {}
and the following objects:
int a;
int* b = &a;
int** c = &b;
int*** d = &c;
then, any of the following is valid:
func_ptr(b);
func_ptr(*c);
func_ptr(**d);
func_ref(*b);
func_ref(**c);
func_ref(***d);
Are the table and explanations correct? Are there any cases left out of the table (except for derived ones like *&n, pointer to pointer etc.)?
Therefore the table not only is incomplete, but cannot possibly contain all possible cases.
Upvotes: 1