C++ Logo

STD-PROPOSALS

Advanced search

Subject: Re: [std-proposals] Review Request: Proposal Ternary Right Fold Expression (P1012)
From: Frank Zingsheim (f.zingsheim_at_[hidden])
Date: 2020-11-08 04:04:01


(Due to the bad formating in the previous mail, I re-mail my previous
email as plain text here, in the hope of a better formating)

Hello Barry

Thank you for the hint to the other proposals.

To the first example with "template for (constexpr": 
This is interesting since it can replace all usages of
std::make_index_sequence which usage in general requires a second
function definition.
However, I cannot find this kind of syntax "template for (constexpr" in
https://wg21.link/P1306.

To the second example with "for ...": 
With this construct you can in principle replace a lot of other fold
expression if you know the combined type generated. But that does not
mean that you do not want to have those fold expressions, e.g.

    template <typename... Values>
    auto add(Values... vs)
    {
        return (... + vs);
    }

vs.

    template <typename... Values>
    auto add(Values... vs)
    {
         auto ret = std::common_type_t<Values...>{};
         for...{
             ret += vs;
         }
         return ret;
    }

The question of the combined type is still the question if you have an
expression like

auto result = (conditions ? values : ... : std::unreachable());

where the values have different types. What should be the return type
for the function covering the for...?

    for...{ 
        if (conditions) {
            return values;
        }
    }

With a classical fold expression, you do not have to worry about the
combined type, since the compiler figures it out for you.

By the way, I cannot find the syntax "for...{}" in https://wg21.link/P1
306, too. There is ony the little bit longer syntax of "for...(){}".
With this longer syntax I am not really sure how to write a combined
for loop over "translators::language" and
"translators::translate_to_english".
As far as I understand P1306 you cannot directly iterate over the types
"translators" and the flavor you revered to a suggestion of Richard
Smith or Andrew Sutton seems not to be formalized in a proposal, yet.

        Frank

Am Montag, den 02.11.2020, 13:37 -0600 schrieb Barry Revzin:
>
>
> On Thu, Jun 11, 2020 at 1:29 PM Frank Zingsheim via Std-Proposals <st
> d-proposals_at_[hidden]> wrote:
> > I have added a paragraph "Comparison to Alternatives already
> > available
> > in C++17"
> >
> > This paragraph contains a comparison of the fold conditional
> > operator
> > to a recursive definition as well as to the usage of the fold with
> > operator|| trick.
> >
> > Please find the updated version on github:
> > https://github.com/zingsheim/ProposalTernaryFold/blob/progress/Prop
> > osal
> > TernaryFold.md
> The first motivating example in the paper is the ability to be able
> to write:
>
>  template <std::size_t... is>
> T test_impl(std::size_t j, std::index_sequence<is...>)
> {
>     return ( (j == is) ? f<is>() 
>             : ... : throw std::range_error("Out of range") );
> }
> template <std::size_t n>
> T test(std::size_t j)
> {
>     return test_impl(j, std::make_index_sequence<n>());
> }
>
> But we have another language feature in the pipeline, expansion
> statements (P1306), that could let me write this differently:
>
> template <std::size_t n>
> T test(std::size_t j)
> {
>     template for (constexpr std::size_t i : std::views::iota(0zu, n))
> {
>         if (i == j) {
>             return f<i>();
>         }
>     }
>     throw std::range_error("Out of range");
> }
>
> I think using the expansion statement is a more straightforward
> implementation that's easier to read. 
>
> Another motivating example from the paper is the one using the
> template parameter pack of translators:
>
> template<class... translators>
> std::string translate_to_english_impl(
>     std::string_view language,
>     std::string_view text)
> {
>     return ( language == translators::language
>              ? translators::translate_to_english(text)
>              : ... : throw std::invalid_argument(
>                          std::string("Unknown language: ").append(
>                              language.begin(),
>                              language.end())) );
> }
>
> Which if we adopt a flavor of expansion statement that could directly
> iterate over a pack (I believe Richard Smith or Andrew Sutton
> suggested for ... at some point, don't remember who):
>
> template<class... translators>
> std::string translate_to_english_impl(
>     std::string_view language,
>     std::string_view text)
> {
>     for ... {
>         if (language == translators::language) {
>             return translators::translate_to_english(text);
>         }
>     }
>     throw /* ... */;
> }
>
> Which again seems to me to be easier to read, and also just generally
> more flexible since you don't have to shove your whole logic into a
> single expression. One of the advantages of the conditional operator
> might be the ability to use it as an expression, but you can always
> wrap the expansion statement in an immediately invoked lambda, so it
> doesn't seem like a huge loss in comparison, at least at first
> glance. 
>
> Are there other use-cases for folding over a conditional operator
> that aren't as neatly solved with expansion statements?
>
> Barry


STD-PROPOSALS list run by std-proposals-owner@lists.isocpp.org

Standard Proposals Archives on Google Groups