Почему нельзя указатель & quot; структуры с константным членом & quot; тип указывает на «структуру с неконстантным членом»?

Этот код не компилируется:

struct s_t {
int a;
};

struct c_s_t {
const int a;
};

s_t s;
c_s_t *c_s = &s;
ibug@ubuntu:~ $ g++ -fsyntax-only t.cpp
t.cpp:10:15: error: cannot convert ‘s_t*’ to ‘c_s_t*’ in initialization
c_s_t *c_s = &s;
^

Однако этот компилируется отлично:

int a, *pa = &a, **ppa = &pa, ***pppa = &ppa;
const int * const * const * const cpcpcpa = pppa;

Я понимаю, что указатель, который более квалифицирован CV на любой Уровень может указывать на менее квалифицированный CV объект на любом уровне, но почему это не то же самое для структур?


Вышеупомянутое постановление проблемы является MCVE более сложной проблемы, где мой друг пытался конвертировать указатели между t_s_t<T> а также t_s_t<const T>, где t_s_t тип структуры шаблона с одним параметром шаблона typename, а также T это произвольный тип.

1

Решение

Причина в том, что s_t а также c_s_t разные типы.

Даже если вы определите c_s_t как:

struct c_s_t {
int a; // <-- non-const!
};

Затем:

s_t s;
c_s_t *c_s = &s;

Это все еще не собирается работать.

4

Другие решения

Ошибка типа — ваша проблема, вы просто пытаетесь назначить неправильные типы.

Это будет работать:

s_t s;
s_t *c_s = &s; //types are matching
1

Эти две разные структуры, и они не конвертируемы. Тот факт, что они имеют одинаковых членов не имеет значения, и даже если вы удалили const от c_s_t, это ничего не изменит.

Ваш другой пример работает, потому что вы применяете модификаторы к одному типу. Например, это совершенно законно:

struct s_t {
int a;
};

s_t s;
const s_t const* cs = &s;
0

Я понимаю, что указатель, более квалифицированный CV на любом уровне, может указывать на менее квалифицированный CV объект на любом уровне

На самом деле это не так, по крайней мере, не так, как вы описали. Только самый верхний CV-квалификатор может быть добавлен произвольно (и, конечно, CV-квалификатор на сам указатель!), Что имеет место как в C, так и в C ++.

Вот контрпример для понятия «любой уровень», взятый прямо из [conv.qual/3] в текущем проекте стандарта:

[ Заметка: Если программа может назначить указатель типа T** на указатель типа const T** (то есть, если разрешена строка № 1 ниже), программа может непреднамеренно изменить const объект (как это делается в строке № 2). Например,

int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc;       // #1: not allowed
*pcc = &c;
*pc = 'C';                    // #2: modifies a const object
}

— конец примечания]

Во всяком случае, тогда вы спросите:

но почему это не то же самое для структур?

Конечно, вы можете указать const T* к T, но это не то, что вы делаете. Это правило не применяется рекурсивно. Классы могут содержать более одного члена, поэтому ваш подход просто не работает в целом (и нет необходимости в специальном правиле для классов с одним членом).

В данном конкретном случае два класса совместимы с макетом, поэтому я ожидаю reinterpret_cast казаться работающим большую часть времени:

struct s_t {
int a;
};

struct c_s_t {
const int a;
};

int main()
{
s_t s;
c_s_t *c_s = reinterpret_cast<c_s_t*>(&s);
}

(живое демо)

Тем не менее, похоже, что псевдонимы по достоинству совместимости макета на самом деле не четко определены так что в конечном итоге вам лучше переосмыслить свой дизайн.

tl; dr: разные типы — это разные типы.

0