...which was deliberately represented in an asymmetric way, to verify the
design's ability to cope with such implementation intricacies. So basically
we have to kick in at LEVEL == 1 and access the implementation differently.
This exercise just shows again, that treating tree structures recursively
is the way to go, and we should do similar when coding up the query-API
for the real GTK toolkit based window elements...
...which can be helpful when a function usually returns a somewhat dressed-up iterator,
but needs to return a specific fixed value under some circumstances
- fix some warnings due to uninitialised members
(no real problem, since these members get assigned anyway)
- use a lambda as example function right in the test
- use move initialisation and the new util::join
this fixes a silly mistake:
obviously we want named sub-nodes, aka. "Attributes",
but we used the anonymous sub-nodes instead, aka. "Children"
Incidentally, this renders the definitions also way more readable;
in fact the strange post-fix naming notation of the original version
was a clear indication of using the system backwards....
up to now, we allowed only initialisation with a precisely matching type.
But this special case seems worth supporting, since it typically occurs
within the "object builder" syntax based on Rec::Mutator
the intention is to rely solely upon this abstract interface
in order to navigate the structure of the actual UI, so the
resolution process remains decoupled from the technicalities
of the actual UI toolkit set.
Through implementation of the corresponding unit test we'll determine
what it actually takes to build such a path resolution algorithm...
obviously, we get a trivial case, when the path is explicit,
and we need a tricky full blown resolution with backtracking
when forced to interpolate wildcards to cover a given UICoord
spec against the actual UI topology.
Do we need it?
* actually not right now
* but already a complete implementation of the ViewSpec concept
requires such a resolution
...to limit them to the UI-Coordinates themselves,
while declining the possibility to mutate the target environment
through the PathResolver. Better handle changes within the
target environment by dedicated API calls on the target elements,
instead of creating some kind of "universal structure"
..this collection of ideas, terms and conclusions has been shaped
since some time within the TiddlyWiki. Since I've now started even
some supporting implementation regarding these concepts, its time
to publish them in the design documentation section of the Website
It is not possible to inherit through boost operators
and defining them explicitly is not that much fuss either.
Plus we avoid the boost include on widely used header
the usual drill...
once there is one additional non explicit conversion ctor,
lots of preferred conversion paths are opened under various conditions.
The only remedy is to define all ctors explicitly, instead of letting the
compiler infer them (from the imported base class ctors). Because this way
we're able to indicate a yet-more-preferred initialisation path and thus
prevent the compiler from going the conversion route.
In the actual case, the coordinate Builder is the culprit; obviously
we need smooth implicit conversion from builder expressions, and obviously
we also want to restrict Builder's ctors to be used from UICoord solely.
Unfortunately this misleads the compiler to do implement a simple copy construction
from non const reference by going through the prohibited Builder ctor, or to
instantiate the vararg-ctor inherited from PathArray.
Thus better be explicit and noisy...
After completing the self-contained UICoord data elements,
the next thing to consider might be how to resolve UI coordinates
against an actual window topology. We need to define a suitable
command-and-query interface in order to build and verify this
intricate resolution process separated from the actual UI code.
Explicitly assuming that those functions are called solely from IterAdapter
and that they are implemented in a typical standard style, we're able to elide
two redundant calls to the checkPoint() function. Since checkPoint typically performs
some non-trivial checks, this has the potential of a significant performance improvement
- we check (and throw ITER_EXHAUST) anyway from operator++, so we know that pos is valid
- the iterate() function ensures checkPoint is invoked right after iterNext,
and thus the typical standard implementation of iterNext need not do the same