Date: Wed, 14 Apr 2021 20:16:38 -0400
I'm a little late to the party here... Don't performance test our
implementation :) We're kind of stuck in the middle of not having had the
right constexpr tools to implement the library well. I'm pretty sure that
loop is quadratic under the hood.
On Fri, Apr 9, 2021, 11:01 PM David Rector via SG7 <sg7_at_[hidden]>
wrote:
>
>
> On Apr 9, 2021, at 9:09 PM, Matus Chochlik via SG7 <sg7_at_[hidden]>
> wrote:
>
> On Sat, Apr 10, 2021 at 2:20 AM David Rector <davrec_at_[hidden]> wrote:
>
>>
>>
>> On Apr 9, 2021, at 8:35 AM, Matus Chochlik via SG7 <sg7_at_[hidden]>
>> wrote:
>> This still happens at compile-time inside of the compiler, so it could
>> allocate the filtered range of metaobjects by using some internal
>> mechanism, that is not exposing generic "dynamic" allocation in consteval.
>> Just saying, in case solving dynamic allocation in constexpr/consteval
>> contexts is something blocking us moving forward with reflection.
>> Or am I missing something?
>>
>>
>>
>> To go further, why should the API include something that requires these
>> allocations in the first place, since they don’t seem particularly
>> efficient (or at least won’t scale well) even if the compiler can handle
>> them internally?
>>
>> That is, should we really be encouraging users to use things like
>> `meta::members_of(reflection, predicate)`, which always necessitates a new
>> allocation?
>>
>> It would be more efficient, and permit more natural programming, to only
>> expose `meta::members_of(reflection)` (i.e. no predicate argument) and
>> instead encourage the user to condition actions on those members via
>> control flow statements during iteration over the compiler’s
>> already-allocated container of members.
>>
>> This would require expanding the contexts in which `consteval {}`
>> metaprograms are permitted, and introducing corresponding fragment kinds to
>> permit injection of entities in those contexts.
>>
>> That is the precisely the argument of this paper:
>> https://isocpp.org/files/papers/P2353R0.html, a cleaned up version of
>> the paper “The syntactic gap” I shared on here awhile ago, which should
>> appear in the next mailing.
>>
>> Matus here is how I would write your `unpack_range`, using P2353 features:
>>
>> ```
>> template <std::experimental::meta::info MO>
>> consteval auto unpack_range() {
>> return unpacked_range<
>> consteval {
>> template for (auto mem : meta::members_of(MO))
>> if (meta::is_constructor(mem))
>> << ^<frag::targ>{ mem }; //a template argument fragment
>> }
>> >{};
>> ```
>>
>> This requires no allocations and is simple to read and write.
>>
>> Something to consider moving forward, given the emphasis on efficiency.
>>
>
> I'm just guessing about Andrew and Wyatt's or Daveed and Faisal's
> motivations here, but based on my reflection implementation experience I'd
> say the reason why we want to do some of the filtering inside of the
> compiler might be that "materializing" the whole:
>
> meta::members_of(MO)
>
> that can then be filtered with arbitrary consteval C++ code may be quite
> "heavy" for some meta-objects. for example if:
>
> auto MO = ^std;
> //or
> auto MO = ^boost;
>
>
> This is true — looping over the entire members_of, with a condition
> inside, seems to be 2-3x slower in this example:
>
> https://cppx.godbolt.org/z/bxGhGPfKo
>
> Presumably this is due to the cost of instantiating each body of the
> `template for`, which involves considerable allocations of its own
> internally (e.g. lots of Stmt::Create(…) inside clang).
>
> So `members_of(refl, predicate)` is indeed useful.
>
> The only point here then is that consteval {} and fragments as described
> in P2353 would allow writing your unpack_range example as:
>
> ```
> template <std::experimental::meta::info MO>
> consteval auto unpack_range() {
> return unpacked_range<
> consteval {
> template for (auto mem : meta::members_of(MO,
> meta::is_constructor))
> << ^<frag::targ>{ mem }; //a template argument fragment
> }
> >{};
> ```
>
>
>
> and I do think that reflecting namespaces and getting (some of) their
> members has valid and useful use-cases.
> When I did the POC implementation for what became the TMP-based reflection
> TS I had metaobject-sequences (or ranges) be meta-objects themselves and
> instantiated the elements lazily. It worked with classes, etc. but I don't
> have much data for reflected namespaces.
>
> --Matus
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
implementation :) We're kind of stuck in the middle of not having had the
right constexpr tools to implement the library well. I'm pretty sure that
loop is quadratic under the hood.
On Fri, Apr 9, 2021, 11:01 PM David Rector via SG7 <sg7_at_[hidden]>
wrote:
>
>
> On Apr 9, 2021, at 9:09 PM, Matus Chochlik via SG7 <sg7_at_[hidden]>
> wrote:
>
> On Sat, Apr 10, 2021 at 2:20 AM David Rector <davrec_at_[hidden]> wrote:
>
>>
>>
>> On Apr 9, 2021, at 8:35 AM, Matus Chochlik via SG7 <sg7_at_[hidden]>
>> wrote:
>> This still happens at compile-time inside of the compiler, so it could
>> allocate the filtered range of metaobjects by using some internal
>> mechanism, that is not exposing generic "dynamic" allocation in consteval.
>> Just saying, in case solving dynamic allocation in constexpr/consteval
>> contexts is something blocking us moving forward with reflection.
>> Or am I missing something?
>>
>>
>>
>> To go further, why should the API include something that requires these
>> allocations in the first place, since they don’t seem particularly
>> efficient (or at least won’t scale well) even if the compiler can handle
>> them internally?
>>
>> That is, should we really be encouraging users to use things like
>> `meta::members_of(reflection, predicate)`, which always necessitates a new
>> allocation?
>>
>> It would be more efficient, and permit more natural programming, to only
>> expose `meta::members_of(reflection)` (i.e. no predicate argument) and
>> instead encourage the user to condition actions on those members via
>> control flow statements during iteration over the compiler’s
>> already-allocated container of members.
>>
>> This would require expanding the contexts in which `consteval {}`
>> metaprograms are permitted, and introducing corresponding fragment kinds to
>> permit injection of entities in those contexts.
>>
>> That is the precisely the argument of this paper:
>> https://isocpp.org/files/papers/P2353R0.html, a cleaned up version of
>> the paper “The syntactic gap” I shared on here awhile ago, which should
>> appear in the next mailing.
>>
>> Matus here is how I would write your `unpack_range`, using P2353 features:
>>
>> ```
>> template <std::experimental::meta::info MO>
>> consteval auto unpack_range() {
>> return unpacked_range<
>> consteval {
>> template for (auto mem : meta::members_of(MO))
>> if (meta::is_constructor(mem))
>> << ^<frag::targ>{ mem }; //a template argument fragment
>> }
>> >{};
>> ```
>>
>> This requires no allocations and is simple to read and write.
>>
>> Something to consider moving forward, given the emphasis on efficiency.
>>
>
> I'm just guessing about Andrew and Wyatt's or Daveed and Faisal's
> motivations here, but based on my reflection implementation experience I'd
> say the reason why we want to do some of the filtering inside of the
> compiler might be that "materializing" the whole:
>
> meta::members_of(MO)
>
> that can then be filtered with arbitrary consteval C++ code may be quite
> "heavy" for some meta-objects. for example if:
>
> auto MO = ^std;
> //or
> auto MO = ^boost;
>
>
> This is true — looping over the entire members_of, with a condition
> inside, seems to be 2-3x slower in this example:
>
> https://cppx.godbolt.org/z/bxGhGPfKo
>
> Presumably this is due to the cost of instantiating each body of the
> `template for`, which involves considerable allocations of its own
> internally (e.g. lots of Stmt::Create(…) inside clang).
>
> So `members_of(refl, predicate)` is indeed useful.
>
> The only point here then is that consteval {} and fragments as described
> in P2353 would allow writing your unpack_range example as:
>
> ```
> template <std::experimental::meta::info MO>
> consteval auto unpack_range() {
> return unpacked_range<
> consteval {
> template for (auto mem : meta::members_of(MO,
> meta::is_constructor))
> << ^<frag::targ>{ mem }; //a template argument fragment
> }
> >{};
> ```
>
>
>
> and I do think that reflecting namespaces and getting (some of) their
> members has valid and useful use-cases.
> When I did the POC implementation for what became the TMP-based reflection
> TS I had metaobject-sequences (or ranges) be meta-objects themselves and
> instantiated the elements lazily. It worked with classes, etc. but I don't
> have much data for reflected namespaces.
>
> --Matus
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
>
> --
> SG7 mailing list
> SG7_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg7
>
Received on 2021-04-14 19:16:51