Explicit pack expansion and the Expansion Operator
Quirin Schroll
qs.il.paperinik at gmail.com
Wed Aug 7 09:57:22 UTC 2024
In D, unlike C++, compile-time sequences (a.k.a. packs, tuples,
alias sequences, and many more) auto-expand. This is usually
desirable, but sometimes, it requires programmers to write
auxiliary constructs to get C++-like pattern expansion.
For example, if `pack` is a parameter pack, in D, `f(pack)` calls
`f` with the pack’s components as parameters. In C++, `f(pack)`
is, generally speaking, invalid, but requires either `f(pack...)`
to expand the pack as parameters for `f` or `f(pack)...` to
create as many invocations of `f` as there are pack members, each
invocation with 1 argument each. And if `fs` is a pack as well,
`fs(pack)...` creates lockstepped invocations: `fs[0](pack[0])` …
`fs[$-1](pack[$-1])`, and the packs involved must be of equal
length.
Essentially, the `...` postfix operator expands packs in lockstep
(and repeats non-packs) into a compile-time sequence.
While C++ requires packs to be expanded (except for some
constructs that handle packs specifically, such as `sizeof...`),
D never did that. The semantics with `...` are simply that if a
declaration or statement is complete and unexpanded packs remain,
those are expanded at the innermost possible place.
Also add the Expansion Operator `opExpand`. When a sub-expression
`e` (possibly a type) is part of a pattern that is to be expanded
and it defines `opExpand`, the sub-expression is considered a
pack and its expansion is considered to be `e.opExpand`. In the
expansion, it is not necessarily indexed, i.e. `opExpand` may be
a sequence, in which case it is indexed, but it may also be a
value, in which case it is repeated. In both cases, though,
`opExpand` keeps expansion from considering sub-expressions. If
`opExpand` is a template, it is passed the length of the
expansion as a `size_t` value argument.
More information about the dip.ideas
mailing list