Remark: I wrote this answer under the assumption that T
in your question represents some actual data type -- I've chosen int
in my examples below.
Background: I was trying to pass a const pointer into a function. [...] I have to consider the cases in which a local pointer is passed in and in which a temporary is passed in (say from a function call return)
You didn't say what you mean by "const pointer". I will first assume you mean a pointer that is itself constant (i.e. the address to which it points cannot be changed).
According to your description, there are basically two ways you get such a pointer:
// Case 1 (what you call a local pointer -- this should be inside some
// function body):
int *const p = 0;
// Case 2, a function that returns a pointer; this is your rvalue case
// in contexts where f() is called and its return value used as a temporary:
int *f()
{ return 0; }
// Note: The temporary returned by this function isn't, strictly speaking,
// constant. It could be modified as long as it is alive. But from
// your description I take it that you have no intentions of doing so
// and/or regard temporaries as generally constant.
Now you can define a function that accepts these two cases as follows:
void g(int *const &arg)
{ }
You can apply this as g(p);
to a constant, local pointer such as p
defined earlier, as well as to a temporary g(f());
. (You could, thirdly, apply it to a non-const local pointer as well, because going from non-const lvalue to const lvalue is never a problem.)
This function g
has a function argument arg
which is defined as a constant, lvalue reference to an int
-pointer. It can bind to a constant (or indeed non-constant) local pointer (such as p
) as well as a temporary, because constant lvalue references, unlike non-constant lvalue references, can do that.
Remark: It's not clear to me why, in this case, you need the function argument to be a reference at all. You could simply declare void g(int *const arg)
(no ampersand) and do without a reference. Reasons include a) You cannot modify it anyway; b) In all real-world implementations, the reference will take just as much (or as little) space as the pointer itself, so there is no point in avoiding a copy.
Anyway. If you want you can also define a second version of g
specifically for rvalue references:
void g(int *&& arg)
{ }
This can only be applied to the temporary, not to the local pointer, because the function argument is defined as an rvalue reference, which can bind to temporaries, but not to lvalues.
However, if by "const pointer" you actually mean a pointer-to-const, i.e. a pointer that can be changed to different addresses, but does not have the power to modify the value stored at those addresses, the declarations are a bit different. The keyword const
must then be put before the asterisk, and for better clarity best before the type specifier int
:
// Declare local pointer-to-const:
const int *p = 0;
// Function that returns a pointer-to-const:
const int *f()
{ return 0; }
A function that can accept these two would then be declared as:
void g(const int *const &arg)
{ }
The first const
means we are talking about pointers-to-const, and the second const
ensures we have a constant lvalue-reference, which can bind to both rvalues and lvalues. Note that this function can not modify what arg
points to, because arg
is declared as a constant lvalue reference. In the case where arg
binds to the temporary, that is probably what we want anyway (as stated above). But in the case where the function is called as g(p);
, we might actually want to modify the local pointer p
from within g
. If you want g
to have this power, you need to define two versions of it:
void g(const int *&& arg)
{ /* Can bind to temporaries, but not modify them. */ }
void g(const int *& arg)
{ /* Can bind to local variables and modify what they point at */ }
Remark 1: Your original declaration const int *const &const
is useless (and not even accepted by GCC). It would mean a "constant reference to a constant pointer to constant int", but since a reference to a constant pointer is implicitly itself a const-reference, the final const
is superfluous (and not provided for by the Standard).
Remark 2: Universal references are not the same as rvalue references. Universal references are declared as T &&arg
where T
is a template parameter. Depending on what T
refers to in each instantiation of the template, this may be an lvalue reference or an rvalue reference -- hence its "universal" character. This has nothing to do with your use case, anyway, though, since you are dealing with pointers T *
here (even if we assume that T
is a template parameter).