The '14 version you have provided is exactly what my proposal generates, but without the indirection. Much of my code involves exactly this pattern, stitched together with a pipeline builder struct, cringy use of the >> operator and helper macros for yield, etc. It suffices, but it's crying out for either a new language, a preprocessor, or a new language feature.

You'll also note that debugging through the callback approach is nothing less than horrific, especially if any pipeline building code is involved (just like with variants). I can't imagine this changing while the code being written is in the form of callbacks.

The reason is that given N components of the pipeline (each yielding a new value to be passed to the next), an unhandled type from component N-1 to component N bubbles an error generating from the first call to component 0. Deciphering the message that comes out is fun, to say the least, and while static_assert is unable to add typenames etc there's no real way around it.

As a language feature, it's easy. The compiler is aware of what you're trying to do, and can provide useful information when you get it wrong.

On Tue, 4 Feb 2020, 15:16 Arthur O'Dwyer via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:
On Tue, Feb 4, 2020 at 8:16 AM Михаил Найденов via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
This definitely steps into both "language variant" and Pattern Matching territory. 
I am not sure what optimization we can expect from "language variant", but PM should give us close to your ideal code

void main(int argc, char const* const* argv){
    inspect(halve(args))
      Numeric x => std::cout << "You passed 2*(" << x << ") arguments\n";
    return 0;
}

The current Pattern Matching proposal doesn't give the programmer any way to write `halve` so that it can actually return either of two alternative types (`unsigned` or `double`) depending on a runtime condition (the evenness of the runtime argument).

However, I don't see anything wrong with the existing C++14 language solution to OP's problem. It's not worth pursuing any crazy core-language gymnastics unless you can provide a use-case that isn't already solvable idiomatically in C++14 (17, 20). Here's the '14 solution:

template<class F>
void halve(unsigned i, const F& f) {
    if (i % 2 == 0) {
        f(i / 2);
    } else {
        f(i * 0.5);
    }
}

int main(int argc, char**) {
    halve(argc, [](auto x) {
        std::cout << "You passed 2*(" << x << ") arguments\n";
    });
    return 0;
}

Short, readable, relatively easy to understand. Certainly easier to understand than anything proposed in the OP.

–Arthur
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals