Я использую псевдонимы типов для pointer
и const pointer
и не понимаю, почему существует разница между возвратом const pointer
и const_pointer
.
Я предположил, что const pointer
в данном случае эквивалентен const int*
, но получаю неверную ошибку компиляции преобразования:
ошибка: недопустимое преобразование из 'const int*' в 'S::pointer {aka int*}
struct S
{
using pointer = int*;
using const_pointer = const int*;
// const_pointer get() const { return &i; } // OK
const pointer get() const { return &i; } // ERROR
int i = {};
};
int main()
{
const S s;
s.get();
}
В этом разница между const (int*)
и (const int)*
.
Я предпочитаю сообщения об ошибках Clang: error: cannot initialize return object of type 'const pointer' (aka 'int *const') with an rvalue of type 'const int *'
. const pointer
и pointer const
одинаковы.
Разница в том, что такое const. В const_pointer
целое число — константа, в const pointer
указатель — константа.
Вся ваша const
путаница исчезнет, если вы будете постоянно ставить const
справа. pointer const
и int* const
означают одно и то же и, очевидно, отличаются от const_pointer
(также известного как int const*
).
@MilesBudnek Я думаю, что отчасти путаница здесь заключается в том, что новички не понимают, что указатель и то, на что он указывает, - это две разные вещи.
@john Это может быть правдой, но даже для людей с немного большим опытом работы с C++ тот факт, что const pointer
— это не то же самое, что вы получили бы при простом текстовом расширении псевдонима (то есть const int*
), является нелогичным.
Как говорят мудрые древние: «ведущая константа вводит в заблуждение».
Я считаю, что будет полезно, если вы перестанете ставить const
слева. Если я перефразирую ваш вопрос:
struct S
{
using pointer = int*;
using const_pointer = int const*;
using pointer_const = int*const;
// const_pointer get() const { return &i; } // OK
// pointer_const get() const { return &i; } // ERROR
pointer const get() const { return &i; } // ERROR
int i = {};
};
int main()
{
const S s;
s.get();
}
Я заменил const int*
на int const*
. Как правило, в C++ const
в типе применяется к компоненту типа слева. Только когда слева нет шрифта, это нарушает это правило.
Когда слева нет компонента, он смотрит на локальное выражение типа, где добавляется const
. Он перемещается «на один шаг вправо» и следует правилу «применить слева». Так:
const pointer
становится
pointer const
И это становится
int*const
нет
int const*
Вторая часть заключается в понимании того, что «указатель на const int» отличается от «константного указателя на неконстантный int». В одном случае мы указываем на то, что не можем изменить; в другом мы не можем указать, на какой объект указываем, но можем изменить этот объект.
Как только вы перестанете разрешать «const слева» — как только вы переведете (по крайней мере, в уме), где const находится слева, на то, что находится справа от того, что он модифицирует, — большая путаница исчезнет.
Последняя часть путаницы заключается в том, что преобразование «слева» в «справа» касается типа, как описано, где находится const
, а не полного фактического развернутого типа.
Именно поэтому я не ставлю const
слева. Набирать текст легко, если вы читаете справа налево и const
находится в правильном месте. int const*
=> Pointer to Const Int
и int*const
=> Const Pointer to int
@MartinYork Восток — лучший, Запад — худший!
const int*
— изменяемый указатель наconst int
. Вашconst pointer
— это константный указатель на изменяемыйint
.