Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is address of non-static member not allowed as template non-type parameter?

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?

like image 628
nav Avatar asked Sep 08 '25 18:09

nav


1 Answers

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.

like image 119
T.C. Avatar answered Sep 10 '25 15:09

T.C.