template <int* ip> struct test {};
struct q {
static int a;
int b;
constexpr q(int b_) : b(b_) {}
};
int i;
constexpr q q0(2);
int main()
{
constexpr test<&i> t1; // Works fine
constexpr test<&q::a> t2; // Works
constexpr test<&q0.b> t3; // Does not work; address of non-static member?
return 0;
}
The declaration of t3 in the above piece of code fails despite the template argument &q0.b
being known during compile time. Some googling revealed that this is disallowed by the standard (section 14.3.2):
[Note: Addresses of array elements and names or addresses of non-static class members are not acceptable template-arguments.
X<&s.m> x4; // error: address of non-static membe
So why exactly is this explicitly disallowed by the standard despite the addresses of non-static members of global variables being unique as well as known during compile-time?
First, to use pointers/references to subobjects, you'd need to be able to mangle them. That's a pretty big undertaking.
Second, and probably more importantly, from N4198:
The restriction that the constant expression must name a complete object is retained to avoid aliasing problems with pointers to subobjects:
struct A { int x, y; } a; template<int*> struct Z; using B = Z<&a.x + 1>; using C = Z<&a.y>; // Are B and C the same type?
To quote Richard Smith,
The answer "yes" is problematic because there are things you can do with a pointer to [
a.y
] that would have undefined behavior if performed on a pointer past the end of [a.x
] The answer "no" is problematic because they (in typical implementations) represent the same address.
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