Phase 8b-Lite: pipe-operator chaining for named parameters
Some checks failed
C++ Tests / test-fast (push) Successful in 1m58s
C++ Tests / test-fast (pull_request) Successful in 2m33s
API Docs / doc-build (pull_request) Successful in 51s
C++ Tests / test-cgal (push) Has been skipped
C++ Tests / test-cgal (pull_request) Failing after 10m32s

Adds `operator|` in `namespace CGAL` so package-local named parameters
can be combined left-to-right without modifying CGAL upstream:

    auto p = CGAL::parameters::gradient_tolerance(1e-12)
           | CGAL::parameters::max_iterations(500)
           | CGAL::parameters::output_uv_map(uv);
    CGAL::discrete_conformal_map_euclidean(mesh, p);

Why not the canonical `.a().b().c()` syntax
───────────────────────────────────────────
CGAL's standard chaining mechanism requires registering each named
parameter as a member function on `Named_function_parameters` via the
`CGAL_add_named_parameter` macro in
`CGAL/STL_Extension/internal/parameters_interface.h` — a vendored
upstream file that conformallab++ deliberately treats as read-only.

Adding member-function chainers for our package-local tags would
require either forking CGAL or modifying the vendored copy.  Neither
is acceptable for a library that wants to remain portable across
future CGAL releases.

The pipe-operator achieves the same compositional semantics via a
free function in `namespace CGAL` (so ADL finds it for
`Named_function_parameters` operands).  Implementation: rebuild the
right-hand-side `Named_function_parameters` with the left-hand-side
as its `Base`, producing an indistinguishable chain that every entry
function accepts unchanged.

Implementation: `code/include/CGAL/Conformal_map/internal/parameters.h`
lines 158-187.  The operator is constrained to right-hand-sides with
`No_property` base (i.e. fresh single-parameter packs from the helper
functions), so it never collides with any future CGAL operator on the
same type.

Tests (2 new, total Phase-8b-Lite suite 15 → 17)
────────────────────────────────────────────────
* CGALPhase8bLite.NamedParamPipe_MultipleParamsTakeEffect
    Chain three parameters; verify all three take effect (tight
    tolerance respected + UV pmap populated + iteration cap honoured).
* CGALPhase8bLite.NamedParamPipe_TwoParams
    Chain two parameters; verify max_iterations(0) blocks the loop
    even when combined with another param.

Full CGAL suite: 234/234 PASSED, 0 SKIPPED (was 232).
Total: 257/257 PASSED, 0 SKIPPED (was 255).
scripts/check-test-counts.sh: OK.

Documentation updates
─────────────────────
* doc/tutorials/add-output-uv-map.md §3.4: "Current limitation: no
  chaining" → "Chaining: use the pipe operator `|`".  Explains why
  CGAL's `.member()` syntax isn't available and shows the `|`
  workaround with a working code example.
* doc/architecture/locked-vs-flexible.md §8: chaining now flagged as
  shipped via pipe; recommended posture says `.member()` chaining
  only if a user pushes for the CGAL-canonical syntax.
* doc/roadmap/porting-status.md §5: API limitations table updated.
* doc/api/tests.md: CGALPhase8bLite row 15 → 17, total 232 → 234.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-22 13:43:52 +02:00
parent eb393537f3
commit 039cc26e36
6 changed files with 149 additions and 25 deletions

View File

@@ -157,28 +157,38 @@ canonical post-processing pass:
Default: `false`. Has no effect unless `output_uv_map` is also passed.
### Current limitation: no chaining
### Chaining: use the pipe operator `|`
The CGAL machinery supports chaining named parameters via `.member()`
syntax for the standard CGAL tags (e.g. `geom_traits`, `vertex_point_map`).
**Package-local tags do not yet have member-function counterparts**, so
CGAL upstream supports chaining via `.member()` syntax for the standard
CGAL tags (e.g. `.geom_traits(...).vertex_point_map(...)`), but the
mechanism requires modifying CGAL's `parameters_interface.h` to register
new member functions on `Named_function_parameters` — which we
deliberately treat as a read-only vendored dependency.
Instead, conformallab++ provides a **pipe-operator overload** in
`namespace CGAL` (so ADL finds it) that achieves the same effect by
left-to-right composition:
```cpp
// DOES NOT COMPILE:
CGAL::parameters::output_uv_map(uv).normalise_layout(true);
auto params = CGAL::parameters::gradient_tolerance(1e-12)
| CGAL::parameters::max_iterations(500)
| CGAL::parameters::output_uv_map(uv);
CGAL::discrete_conformal_map_euclidean(mesh, params);
```
is currently rejected. Pass one parameter per call instead. This is
the same limitation noted in `test_cgal_phase8b_lite.cpp`:
Read as: "first apply gradient_tolerance, then max_iterations, then
output_uv_map". The result is a `Named_function_parameters` chain
indistinguishable from what `.gradient_tolerance(...).max_iterations(...)
.output_uv_map(...)` would have produced, so every entry function in the
package accepts it as-is.
```cpp
// Named-parameter chaining (`a.b().c()`) is not currently supported on
// the package-local tags; pass one parameter per call instead.
```
Implementation: see the `operator|` in
`code/include/CGAL/Conformal_map/internal/parameters.h`.
Tests: `CGALPhase8bLite.NamedParamPipe_MultipleParamsTakeEffect` +
`NamedParamPipe_TwoParams`.
Adding member-function chaining is a separate Phase 8b extension —
requires writing a derived `Named_function_parameters` subclass that
exposes `.output_uv_map(...)`, `.normalise_layout(...)`, etc.
The `.member()` chaining of CGAL standard tags continues to work
unchanged — `|` is added alongside, not replacing.
---