tuple_unfold(3) | tuple_unfold(3) |
tuple_unfold - generate tuple from seed
#include <cfl/tuple/functions/tuple_unfold.hpp>
// generic form
tuple_unfold <PY, FY, SY> (init, u...);
// convenience overloads
tuple_unfold <N> ();
tuple_unfold <N> (f);
tuple_unfold <N> (g);
tuple_unfold <3> () == tuple (0,1,2);
tuple_unfold <3> ([] () { return 0; }) == tuple (0,0,0);
tuple_unfold <3> ([] (int u) { return u*2; }) == tuple (0,2,4);
An unfold
can be thought of as the opposite of a fold
. Where a fold reduces
many values to a singular value, an unfold generates many values from a
singular value. Its general form may be a bit awkward for the most common user
cases, so some convenience overloads are provided.
The convenience forms generate a tuple
with N
elements. The first form
creates consecutive size_t
elements starting at zero. The second form creates
elements from invocations of the nullary function f
. The third form creates
elements by invoking the unary function g
using the tuple index as argument.
The convenience forms all use a state of type std::integral_constant <size_t, N>
(for which CFL has a shorthand natural_t <N>
), with an initial N = 0
.
The third conventience form converts the natural_t <N>
state to a size_t
run-time value before applying it to g
.
The generic form assumes three factory arguments, PY
, FY
and SY
, an
initial state init
, and an optional list U of convenience values.
PY <STATE, U...> // predicate
FY <STATE, U...> // new value
SY <STATE, U...> // new state
The unfold proceeds stepwise by first asserting the predicate is true, then generating a new value, and finally retreiving the next state. All necessary arguments can be included in the state, but for convenience the optional list U will be passed to factories as well. This is to releive the burden of bundling arguments.
As the element types of the resulting tuple
is determined at compile-time, the
value of the predicate PY
and the next state SY
must be available at
compile-time. There is no restriction on the types of the generated elements -
the general case allows for arbitrary types to be returned from FY <STATE, U...>
.
A tuple
with values.
Due to the convenience overloads, tuple_unfold
is a function template, not a
function object as customary. As a consequence, it can not be used as argument
to a function as easily.
Adhering to the general form, the result is not a constexpr
. (A restriction
on the state to be a type only and not hold run-time values would be enough to
lift this limitation.)
As the state may have a run-time value, this implies a run-rime union storage
for temporary states during the unfold. Although literal types stored in core
unions are constant expressions, the implemenation of a variadic union is not
a constant expression - at least not in void
expressions. Whether this is a
limitation of the language or the compiler remains to be seen. Anyway,
constexpr
under these conditions is a C++14 feature - which is not yet
supported by the nvcc compiler (as of version 8.0).
tuple_fold(3), conventions(5), union(3), variant(3)