Consider the following code:
int main() {
const int i = 42;
auto *p = &i; // p is const int *. const is low level const
auto &q = i;
The const
in case of reference is not really low-level (as opposed to the pointer case).
typeid
is applied to the type of expression q
. This expression immediately loses its reference type, per the following general rule
5 Expressions
5 If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.
Expressions in C++ never have visible "reference" types, which also means that typeid
cannot "see" references. It cases like this it always sees lvalues or xvalues of non-reference types. In your case typeid
sees lvalue expression of type const int
as its agument.
The rest follows from the definition of typeid
behavior
5.2.8 Type identification
5 If the type of the expression or type-id is a cv-qualified type, the result of the typeid expression refers to a std::type_info object representing the cv-unqualified type.
I.e. typeid
simply ignores top-level const-qualification.
In pointer case the const-qualification you are referring to is a not a top-level one. It is not lost under typeid
.
Note also that the definition of typeid
contains the following rule
4 When typeid is applied to a type-id, the result refers to a std::type_info object representing the type of the type-id. If the type of the type-id is a reference to a possibly cv-qualified type, the result of the typeid expression refers to a std::type_info object representing the cv-unqualified referenced type.
Its purpose is to make the behavior of typeid
applied to typenames consistent with the above behavior of typeid
applied to expressions. I.e. typed
applied to typename ignores references and also ignores cv-quailifications that become top-level after reference removal.
For some extra examples
typeid(const int) == typeid(int); // <- true
typeid(const int &) == typeid(int); // <- true
typeid(int *) == typeid(int *const); // <- true
typeid(int *) == typeid(const int *); // <- false