1- Why doesn't my first example work?
The parameter is a reference to a pointer to const. &a
- which is the argument - is a pointer to non-const. Pointer to const and pointer to non-const are different types. The argument could be implicitly converted to a pointer to const type. However, the result of that conversion is an rvalue - it is a temporary object. The parameter of the function is an lvalue reference to non-const, and such references cannot be bound to rvalues1.
if a regular constant can be passed like this:
In that example, you have an lvalue reference to const. Lvalue references to const can be bound to rvalues. In the case of test(a)
, the type of the referred object even matches with the type of the reference, so there isn't even a conversion and parameter refers directly to the passed argument.
Why isn't it doing the same in the case of passing a pointer by reference?
See 1 above
Why do I have to specify const above before int *b for it to compile?
Because the parameter is an lvalue reference to non-const pointer to const. If you don't specify const there, then you have a pointer to non-const, and thus you would need a conversion such as in the case of &a
and thus the result would be an rvalue and thus the lvalue reference to non-const cannot be bound.
You could make the pointer function analogous to the integer example by using a reference to const that matches with the type of the argument:
int* a;
// analogous to your int example:
void test1(int* const& in);
test1(&a); // OK, no conversion
// now, we have a reference to non-const,
// but that's fine since there is no conversion:
void test2(int* const& in);
test2(&a); // OK, no conversion
// now there is conversion, but that's fine since
// it is an lvalue reference to const:
void test3(const int* const& in);
test3(&a); // OK, conversion
// there's a conversion here and the reference isn't
// const but that's fine since it's an rvalue reference:
void test4(const int*&& in);
test4(&a); // OK, conversion
Or, you could make the integer example fail by making it analogous to the pointer example by introducing a conversion and by using a reference to non-const:
long b;
// analogous to your pointer example:
void test5(int& in);
test5(b); // NOT OK
Note that whether the referred type is a pointer to const or pointer to non-const is entirely separate from the reference being a reference to const or non-const.