I was trying to verify in a static_assert
that a program had really two distinct classes produced from a template by comparing the pointers on their static fields. After some simplifications the program looks as follows:
template<int N> struct C {
static int x;
};
template<int N> int C<N>::x = 0;
int main() {
static_assert(&C<0>::x != &C<1>::x);
}
Clang is ok with it, but GCC prints the error:
error: non-constant condition for static assertion
demo: https://gcc.godbolt.org/z/o6dE3GaMK
I wonder whether this type of check is really allowed to do in compile time?
Compile-time equality comparison of the pointers on static class members is allowed.
The problem with original code was only in GCC and due to old GCC bug 85428.
To workaround it, one can explicitly instantiate the templates as follows:
template<int N> struct C {
static int x;
};
template<int N> int C<N>::x = 0;
template struct C<0>;
template struct C<1>;
int main() {
static_assert(&C<0>::x != &C<1>::x);
}
This program is now accepted by all 3 major compilers, demo: https://gcc.godbolt.org/z/Kss3x8GnW
This should be more comment than an answer, but it does not fit in a readable way in the comments section.
So regarding the intent of the question:
I was trying to verify in a
static_assert
that a program had really two distinct classes produced from a template by comparing the pointers on their static fields
Your code snippet is a template for a class:
template<int N> struct C {
static int x;
};
This means that it is not a class by itself but a blueprint. The actual classes are C<0>
and C<1>
. If the values chosen for N
are distinct then the resulting classes are distinct.
To figure out if two types are distinct you would use (as you correctly mention in your comment) std::is_same_v
:
static_assert( !std::is_same_v<C<0>,C<1>>);
No matter if static_assert(&C<0>::x != &C<1>::x);
is valid or not you shouldn't use it to figure out if those types are distinct from the perspective of the language. In the worst case you would - due to requesting the memory address of a member - prevent the compiler to do some optimizations it could before.
Now you could say the compiler can do optimizations based on the as-if and share parts between those types, so they are not distinct on the binary level (distinct on the language and distinct in the binary are two different things).
But to which degree those are distinct on the binary level cannot be really tested within the code due to the same as-if rules.
Let's assume for a moment that static_assert(&C<0>::x != &C<1>::x);
would work, then &C<0>::x != &C<1>::x
has to evaluate to true
, because the C<0>
and C<1>
are distinct type. This could happen due to two things:
Because you ask for the memory address of x
for C<0>
and C<1>
you actually prevent the compiler to do an optimization after which they would share x
on the binary level, so the memory address on the binary level is actually different.
The compiler still does the optimization so that x
is shared between C<0>
and C<1>
. But the outcome of &C<0>::x != &C<1>::x
would still be true
because it has to be true
according to the as-if rule. So even if the address of x
for both distinct types C<0>
and C<1>
would be the same on the binary level the static_assert
test would be true
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With