C++ Logo

sg7

Advanced search

[SG7] Slicing packs vs slicing ranges

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Wed, 18 Nov 2020 19:55:02 -0600
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

Received on 2020-11-18 19:55:19