skypjack skypjack - 1 year ago 51
C++ Question

The void(), the comma operator (operator,) and the impossible (?) overloading

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:


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

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

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
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.

Answer Source

The relevant clause for this is [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 []), 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 by 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.