Date: Sun, 08 Nov 2020 10:55:06 +0100
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://wg
21.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/P1306, 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
> 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
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://wg
21.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/P1306, 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
> 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
Received on 2020-11-08 03:55:18