Speaking of unpacking meta::info ranges, I personally see operator |something|... as different type of operator |something| which is to me same thing as having multiple operators per AST type. 

So if I know the something is a pack/range, it should reify into a pack/range. In the example we can go with library solution:

enum E { A, B, C};
constexpr auto enums = meta::enumerators_of(reflexpr(E));
int vals[] {|meta::pack_from_range(enums)|...};

And here the ... is unpacking an ordinary pack created by the reify operator.

Hana

On 19. 11. 2020, at 2:55, Barry Revzin via SG7 <sg7@lists.isocpp.org> wrote:

Hey all,

Andrew's Metaprogramming paper allows for the following syntax (pg 19 from D2237R1):

enum E { A, B, C};
constexpr auto enums = meta::enumerators_of(reflexpr(E));
int vals[] {|enums|... };

That is, you can directly expand a splice of enums, because it's a constexpr range. But this is the same exact syntax that would happen if we had a parameter pack:

template <meta::info... enums>
void f() {
   int vals[] { |enums| ... };
}

And I'm concerned about implicitly treating both ranges and packs the same. I think this could run into similar issues as we saw with expansion statements, and similar issues to the case I talk about in P1858 (the context here was directly expanding a tuple into its underlying parts, which is similar to expanding a range of meta::infos into its infos):
template <typename T, typename... U>
void call_f(T t, U... us)
{
    // Is this intended to add 't' to each element in 'us'
    // or is intended to pairwise sum the tuple 't' and
    // the pack 'us'?
    f((t + us)...);
}
Here, it's easy for me to come up with examples of wanting either choice:
* call_f(tuple(1, 2), 3, 4) could be intended to call f(4, 6), doing the pairwise sum.
* call_f(point{1, 2}, point{0, 1}, point{3, 7}) could be intended to call f(point{1,3}, point{4,9}), adding 't' to each element.

A similar thing could come up here - where we have a range of meta::info and a pack and may want to expand the range and may not want to:

template <typename E, typename... Args>
void foo(Args... args) {
    constexpr auto enums = meta::enumerators_of(reflexpr(E));
    g(|impl(enums, args)|...);
}
enum E { A, B, C };
void bar() {
    foo<E>(1, 2, 3);
}

Are we calling impl(enums, 1) or are we calling impl(reflexpr(E::A), 1)?

Barry
--
SG7 mailing list
SG7@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/sg7