Date: Fri, 21 Jan 2022 07:32:39 +0100
On Thu, Jan 20, 2022 at 5:24 PM David Rector via SG7 <sg7_at_[hidden]>
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
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
Received on 2022-01-21 06:32:52