15

According to N4295 C++17 will allow me to calculate the sum of an unknown number of arguments thus:

template<typename ... T>
int sum(T...t)
{
    return (... + t);
}

The document further states that I could use operators such as == or > instead of +. Can anybody come up with a sensible example of when I would want to use == or > in such a construct?

(I realize that people can define == and > to do strange things to strange classes, but surely that violates good practice. Writing a > b > c > d is hardly ever a good idea, is it?)

Thomas McGuire
  • 5,308
  • 26
  • 45
oz1cz
  • 5,504
  • 6
  • 38
  • 58
  • If you use a binary fold with some special starting element, maybe you could say `(apply_op() == ... == t)` to make the `apply_op`'s `operator==` do the right thing? – Johannes Schaub - litb May 21 '16 at 10:07
  • From what I remember, unary folds were removed for +. You'd have to write `(T{} + ... + t)` or `(t + ... + T{})` (or whichever value makes sense for you). – chris May 22 '16 at 13:45
  • @chris They have only been removed when the parameter pack is empty. As long as there is at least one element in `...t` the function above still works as expected. – Morwenn May 23 '16 at 15:24
  • @Morwenn, Interesting, I never caught that part. – chris May 23 '16 at 15:49
  • @chris Well, the goal was to prevent having a default `int`-typed `0` when no parameters were given, which might cause incorrect overloads to be called in this specific case. When parameters have been provided, the return type depends on the types of the parameters, which is generally the intended behaviour. Only the empty case was tricky. – Morwenn May 24 '16 at 07:14

3 Answers3

11

I would be an interesting feature if chained comparisons where handled like in Python where a < b < c is interpreted as a < b and b < c with a single evaluation of b. Unfortunately, this is not the case in C++ and even in strange cases, folding comparison operators indeed hardly makes sense.

Note that there was a proposal (P0313) to actually remove the operators ==, !=, <, >, <= and >= from the operators handled by fold expressions altogether. It has been discussed during the June 2016 committee meeting in Oulu. The motivation for the removal was rather brief:

Comparison operators don't make much sense in fold-expressions; they expand into expressions that have surprising effects, and are thus useful for dsl-metaprogrammers only. [...] It would be nice to be able to fix expressions like a < b < c. That would require a time machine. Not repeating the problem for fold-expressions seems doable.

That said the proposal was rejected.

Morwenn
  • 21,684
  • 12
  • 93
  • 152
  • 1
    One can overload such operators to behave in different manner, where folding would result in some nice feature. Maybe ;) – Zereges May 21 '16 at 12:55
  • 2
    I would favor a "mix folding" where you can say "t op1 ... op2" for unary folds and "t op1 ... op2 e" for binary folds which expands to "t1 op1 t2 op2 t2 op1 t3 ...". – Johannes Schaub - litb May 21 '16 at 15:50
  • @JohannesSchaub-litb Time to write another proposal? :p – Morwenn May 21 '16 at 17:41
  • @JohannesSchaub-litb Or rather, have a syntax that takes `t...` and `op`, and produces a pack `t1 op t2` `...` (each adjacent pair). Then applying standard folding to *that* gives you what you want. Now, if we could have operators that returned packs this could be defined as `(except_last(t) op1 except_first(t)) op2 ...` or somesuch. – Yakk - Adam Nevraumont May 29 '16 at 04:14
2

This is not a "direct folding of == alone" but rather a "&& folded with an expression involving ==". However this is the solution I use to compare values and maybe this is also the kind of application you had in mind.

This works for me, for both g++ and clang++

template <typename TYPE, typename... TYPE_TAIL>
constexpr bool same_value([[maybe_unused]] TYPE value, TYPE_TAIL... value_tail)
{
  return (... && (value == value_tail));
}

static_assert(same_value(3));
static_assert(same_value(3, 3));
static_assert(!same_value(3, 1));
static_assert(same_value(3, 3, 3));
static_assert(!same_value(3, 1, 3));

int main() {}

Compilation:

clang++ -std=c++1z testFold.cpp -o testFold

(version: clang version 5.0.0-+rc2-1 (tags/RELEASE_500/rc2))

or

g++ -std=c++17 testFold.cpp -o testFold

(version: g++ (Debian 7.2.0-8) 7.2.0)

The [[maybe_unused]] prevents compiler to warn you when same_value(one_arg) is called with only one argument as in that case the function returns the neutral value for the && operator (which is true).

Picaud Vincent
  • 10,518
  • 5
  • 31
  • 70
1

On usecase would be expression templates, for which the comparison operators (e.g. operator ==) return a class object instead of a bool.

I too struggle to come up with a useful example even here, though.

Thomas McGuire
  • 5,308
  • 26
  • 45