On Thu, Jan 20, 2022 at 5:24 PM David Rector via SG7 <sg7@lists.isocpp.org> wrote:


Re namespaces, does the fact that the number of members can increase between reflections require further specification?

Well we don’t currently propose such a facility (mostly because we haven’t found a compelling use case and it might cause some surprises).
If we did, I’d expect that the answer to your “still error?” questions below would be “yes”.

Daveed


I’m a little confused — are you are saying it is an error to declare a namespace after having reflected it — i.e. the second `namespace foo {…}` is illegal?  Or is the use of the subscript operator the problem?  

If the latter the example should actually have been written fooMemsA/B = members_of(^foo).data(), i.e. fooMemsA/B is an `info*`, so span's operator[] def isn’t called to check that the index is in bounds; instead only the constant evaluation implementation is responsible for checking if the result of the pointer addition invoked by fooMemsA[15] is in bounds.  

So the real question is, what an implementation is required to do to ensure persistent memory storage (in decreasing order of memory usage, which as you note might be substantial for namespaces):
1. allocate a new array for every distinct reflection of a namespace’s members or
2. allocate a new array if and only if a) this is the first reflection of those members or b) new members have been added since the last reflection of its members, or
3. allocate a new vector of members the first time a namespace is reflected, then add to it as more namespaces are declared, moving the underlying array around as the capacity is exceeded, and (assuming we don’t want to invalidate old pointers) use an additional layer of indirection during constant evaluation of these pointers to ensure that multiple calls to members_of(^foo).data() are always "equal", i.e. point to the most recent allocation, even though multiple calls to members_of(^foo).size() may be different.
4. same as #3, but only add new members to the internal vector of namespace members upon a subsequent reflection.

#1: "still error?" is an error both times
#2: ""
#3: first "still error?" is an error, second is not
#4: neither are errors

IIRC when what eventually became the reflection TS was discussed this issue was decided the following way:

namespace example {
void foo();
void bar();
}

using mo1 = reflexpr(example);

namespace example {
void baz();
void qux();
}

using mo2 = reflexpr(example);

// the two metaobjects are different
static_assert(!is_same_v<mo1, mo2>);

// but they reflect the same base level entity
static_assert(reflects_same_v<mo1, mo2>);

and (in the TS there is not get_all_members operation for namespaces, but if there was) these would return two different answers

get_size_v<get_all_members_t<mo1>>; // 2
get_size_v<get_all_members_t<mo2>>; // 4