为什么 "struct with const member" 类型的指针不能指向 "struct with non-const member"?
Why can't a pointer of a "struct with const member" type point to a "struct with non-const member"?
此代码无法编译:
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;
我知道在 any 级别上更符合 CV 限定的指针可以指向任何级别上不太符合 CV 限定的对象,但为什么不一样对于结构?
上面的问题陈述是一个更复杂问题的MCVE,我的朋友试图在t_s_t<T>
和t_s_t<const T>
之间转换指针,其中t_s_t
是模板结构类型有一个模板参数 typename
,T
是任意类型。
这两个是不同的结构,它们不可转换。他们拥有相同成员这一事实无关紧要,即使您从 c_s_t
中删除 const
,也不会改变任何内容。
您的另一个示例之所以有效,是因为您将修饰符应用于一种类型。例如,这是完全合法的:
struct s_t {
int a;
};
s_t s;
const s_t const* cs = &s;
原因是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;
还是不行。
类型错误是您的问题,您只是在尝试分配错误的类型。
这可行:
s_t s;
s_t *c_s = &s; //types are matching
I understand that a pointer that is more CV-qualified at any level can point to a less CV-qualified object at any level
这实际上不是真的,至少不是你描述的那样。只有最顶层的 CV 限定符可以任意添加(当然,指针本身的 CV 限定符!),C 和 C++ 都是这种情况。
这是 "any level" 概念的反例,直接取自当前草案标准中的 [conv.qual/3]
:
[ Note: If a program could assign a pointer of type T**
to a pointer of type const T**
(that is, if line #1 below were allowed), a program could inadvertently modify a const
object (as it is done on line #2). For example,
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}
— end note ]
不管怎样,那你问:
but why isn't it the same for structures?
当然,您可以将 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);
}
(live demo)
但是,看起来 aliasing on the merits of layout-compatibility is not actually well-defined 所以最终你最好重新考虑你的设计。
tl;dr: 不同的类型是不同的类型。
此代码无法编译:
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;
我知道在 any 级别上更符合 CV 限定的指针可以指向任何级别上不太符合 CV 限定的对象,但为什么不一样对于结构?
上面的问题陈述是一个更复杂问题的MCVE,我的朋友试图在t_s_t<T>
和t_s_t<const T>
之间转换指针,其中t_s_t
是模板结构类型有一个模板参数 typename
,T
是任意类型。
这两个是不同的结构,它们不可转换。他们拥有相同成员这一事实无关紧要,即使您从 c_s_t
中删除 const
,也不会改变任何内容。
您的另一个示例之所以有效,是因为您将修饰符应用于一种类型。例如,这是完全合法的:
struct s_t {
int a;
};
s_t s;
const s_t const* cs = &s;
原因是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;
还是不行。
类型错误是您的问题,您只是在尝试分配错误的类型。
这可行:
s_t s;
s_t *c_s = &s; //types are matching
I understand that a pointer that is more CV-qualified at any level can point to a less CV-qualified object at any level
这实际上不是真的,至少不是你描述的那样。只有最顶层的 CV 限定符可以任意添加(当然,指针本身的 CV 限定符!),C 和 C++ 都是这种情况。
这是 "any level" 概念的反例,直接取自当前草案标准中的 [conv.qual/3]
:
[ Note: If a program could assign a pointer of type
T**
to a pointer of typeconst T**
(that is, if line #1 below were allowed), a program could inadvertently modify aconst
object (as it is done on line #2). For example,int main() { const char c = 'c'; char* pc; const char** pcc = &pc; // #1: not allowed *pcc = &c; *pc = 'C'; // #2: modifies a const object }
— end note ]
不管怎样,那你问:
but why isn't it the same for structures?
当然,您可以将 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);
}
(live demo)
但是,看起来 aliasing on the merits of layout-compatibility is not actually well-defined 所以最终你最好重新考虑你的设计。
tl;dr: 不同的类型是不同的类型。