1

此代码无法编译:

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是任意类型。

4

4 回答 4

4

原因是s_tc_s_t是不同的类型。

即使您定义c_s_t为:

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

然后:

s_t s;
c_s_t *c_s = &s;

它仍然无法正常工作。

于 2018-10-05T09:11:26.053 回答
1

类型错误是您的问题,您只是试图分配错误的类型。

这会起作用:

s_t s;
s_t *c_s = &s; //types are matching
于 2018-10-05T09:13:11.930 回答
0

这两个是不同的结构,它们是不可转换的。他们拥有相同成员的事实无关紧要,即使您const从中删除c_s_t,也不会改变任何事情。

您的另一个示例有效,因为您将修饰符应用于一种类型。例如,这是完全合法的:

struct s_t {
    int a;
};

s_t s;
const s_t const* cs = &s;
于 2018-10-05T09:11:03.287 回答
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
}

——尾注]

无论如何,然后你问:

但为什么结构不一样?

当然,您可以将 a 指向const T*a T,但这不是您正在做的事情。此规则不适用于递归。类可以容纳多个成员,因此您的方法通常不起作用(并且对于单成员类不需要特殊规则)。

在这种特殊情况下,这两个类是布局兼容的,所以我希望 areinterpret_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:不同的类型是不同的类型。

于 2018-10-05T09:18:15.520 回答