Reputation: 37307
This code doesn't compile:
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;
^
However this one compiles perfectly:
int a, *pa = &a, **ppa = &pa, ***pppa = &ppa;
const int * const * const * const cpcpcpa = pppa;
I understand that a pointer that is more CV-qualified at any level can point to a less CV-qualified object at any level, but why isn't it the same for structures?
The above problem statement is a MCVE of a more complex problem, where my friend was trying to convert pointers between t_s_t<T>
and t_s_t<const T>
, where t_s_t
is a template struct type with one template parameter typename
, and T
is an arbitrary type.
Upvotes: 1
Views: 172
Reputation: 385295
I understand that a pointer that is more CV-qualified at any level can point to a less CV-qualified object at any level
This isn't actually true, at least not in the way you've described. Only the topmost CV-qualifier can be added arbitrarily (and, of course, a CV-qualifier on the pointer itself!), which is the case in both C and C++.
Here's a counter-example for the "any level" notion, taken straight from [conv.qual/3]
in the current draft standard:
[ 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 ]
Anyway, then you ask:
but why isn't it the same for structures?
Sure, you can point a const T*
to a T
, but that's not what you're doing. This rule doesn't apply recursively. Classes can hold more than one member so your approach just doesn't work in general (and there's no need for a special rule for single-member classes).
In this particular case, the two classes are layout-compatible, so I'd expect a reinterpret_cast
to appear to work most of the time:
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);
}
However, it appears that aliasing on the merits of layout-compatibility is not actually well-defined so ultimately you're better off rethinking your design.
tl;dr: Different types are different types.
Upvotes: 0
Reputation: 2053
Type error is your problem you are simply trying to assign the wrong types.
This would work:
s_t s;
s_t *c_s = &s; //types are matching
Upvotes: 1
Reputation: 24788
The reason is that s_t
and c_s_t
are different types.
Even if you define c_s_t
as:
struct c_s_t {
int a; // <-- non-const!
};
Then:
s_t s;
c_s_t *c_s = &s;
It is still not going to work.
Upvotes: 4
Reputation: 39390
Those two are different structs, and they're not convertible. The fact that they have the same members is irrelevant, and even if you removed const
from c_s_t
, it wouldn't change anything.
Your other example works because you're applying modifiers to one type. For example, this is perfectly legal:
struct s_t {
int a;
};
s_t s;
const s_t const* cs = &s;
Upvotes: 0