Suppose you can do this, you can write the following:
const int c = 0; void updatePointer(const int* &i) { i = &c; } int main() { int *ptr; updatePointer(ptr); *ptr = 1;
The purpose of const is to ensure that the user code cannot try to modify the const object if it does not contain const-cast (or the equivalent). Therefore, the compiler must abandon this code. Denying const int*& binding from binding to int* is the only place in the code above that is reasonable for the compiler to refuse: every other line is fine.
For the same reason, you cannot implicitly convert int** to const int ** .
Besides the motivation from the point of view of security const, you might think if in terms of int* is another type from const int* , which is simply converted to it. Similarly, you can convert int to double , but double& cannot bind to an int lvalue value. This is not a complete reason, because actually int* and const int* have the same size and representation, while int and double do not. Thus, there may be a special case to allow him, if not for the fact that he would violate the const system.
The reason C ++ has both const and non-constant overloads for strchr is related to this problem: your updatePointer function changes its input rather than returning an updated value, but the principle is similar. The C-style strchr single allows you to "wash" a pointer to a constant into a pointer to a non-const without cast, and this is a hole in the const system. C ++ (a) has an overload and (b) has a more strict type system than C, so it closes this hole.
If you want your real updatePointer function updatePointer work like strchr - look at the data pointed to and calculate the new value for the pointer, then you are in the same situation as strchr . This is regardless of what it does with the new value (return it in the case of strchr , write it back in the case of updatePointer ), because the problem is that you want the new pointer to have the same const qualification as input. You need to specify either const, or non-constant overload, or a function template.
If you only need your real updatePointer function to move the pointer a certain distance, regardless of the data it points to, you can use std::advance instead.