21

Consider the following struct:

struct S {};

In C++14, the definition below is valid:

constexpr auto f() { return S{}, 'c'; }

As well as the following one:

constexpr auto f() { return S{}, void(); }

Now, consider the following, working snippet that involves the first of the two definitions:

#include<type_traits>

struct S {};

constexpr int operator,(S, char) { return 42; }
constexpr auto f() { return S{}, 'c'; }

int main() {
    constexpr int i{f()};
    static_assert(i == 42, "!");
    static_assert(std::is_same<decltype(f()), int>::value, "!");
}

Speaking not so technically, the overload of the comma operator intercepts the couple S{}, 'c' and returns an integer, as correctly verified in the main function.

Now, suppose I want to do the same with the second definition of f:

constexpr auto f() { return S{}, void(); }

In this case, the comma operator should intercept the form S{}, void().
Neither the following definition works (for obvious reasons):

constexpr int operator,(S, void) { return 42; }

Nor the one below (that would have worked in the previous case):

template<typename T> constexpr int operator,(S, T &&) { return 42; }

Is there any way to overload the comma operator so as to deal with S{}, void()?
Isn't it otherwise a lack in the standard, for it allows to use the comma operator that way, but doesn't give you the chance to overload the same operator (even if the standard mentions that overloaded functions involving S are allowed)?


Note: this question is made for the sake of curiosity. Please, avoid comments like do not do that or it is not good practice. I'm not planning to do that in production environments. Thank you.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 3
    That's intriguingly crazy ;) – Jesper Juhl Sep 15 '16 at 15:27
  • @JesperJuhl Yes, I know. Standard guerrilla. I'm exploring the most obscure corners of the language. :-) – skypjack Sep 15 '16 at 15:28
  • Changing the operator `,` to `+` gives an "argument may not have 'void' type" error. – kennytm Sep 15 '16 at 15:29
  • 3
    This is really impossible. Casting to `void` is the standard trick to prevent people breaking your loops like `for(...;++it1, ++it2)` by overloading the comma operator for their iterator class. – Baum mit Augen Sep 15 '16 at 15:29
  • @kennytm This is not a surprise indeed. The question is about `operator,`, not `operator+`. – skypjack Sep 15 '16 at 15:32
  • @skypjack I don't see any different between them in terms of operator overloading :) – kennytm Sep 15 '16 at 15:32
  • 1
    @kennytm Oh, ok, I see your point now. Well, anyway, note that `1 + void()` is not valid, `1, void()` is valid instead. – skypjack Sep 15 '16 at 15:34
  • Interesting, I would like to know what's for the downvotes, it would help to improve the question at least... – skypjack Sep 15 '16 at 15:34
  • 4
    @skypjack Yes, but some operators lose their special behavior when overloaded, e.g. `&&`, `||` are no longer short-circuiting. – kennytm Sep 15 '16 at 15:35

1 Answers1

28

The relevant clause for this is 13.3.1.2/9 [over.match.oper] in N4140:

If the operator is the operator ,, the unary operator &, or the operator ->, and there are no viable functions, then the operator is assumed to be the built-in operator and interpreted according to Clause 5.

As void() is never a valid function argument (see 5.2.2/7 [expr.call]), there never is a viable function and thus the built-in , will be used.

So no, what you are trying to do is not possible.

In fact, writing an iterator loop like this

for(...; ++it1, (void)++it2)

is a standard way to prevent users from breaking your code by overloading , for their iterator types by enforcing the built-in operator , to be used. (Note that I am not saying you need to do this in your everyday code. It very much depends on its actual use. This is standard library level of paranoid.)


Regarding the standard clause you linked:

The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed for specific class and enumeration types by defining operator functions that implement these operators.

But such a function cannot be defined because, as I said above, void() is never a valid function argument.

Now whether or not this is an oversight/problem in the standard is open to debate.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182