C++ Logo

std-proposals

Advanced search

Re: Review Request: Proposal Ternary Right Fold Expression (P1012)

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Mon, 2 Nov 2020 13:37:22 -0600
On Thu, Jun 11, 2020 at 1:29 PM Frank Zingsheim via Std-Proposals <
std-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/Proposal
> 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

Received on 2020-11-02 13:37:40