August 07

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.

August 07

On Wednesday, 7 August 2024 at 09:57:22 UTC, Quirin Schroll wrote:

>

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.

[...]

About the syntax I think that using the system of type properties (to be perfectly clear I speak about things like .stringof) would be more judicious than a new operator. Properties dont require parser modifications. So .expand.