0

Since C++11 we can write lambdas such as:

auto foo = [a, b]() { return a+b; };

with a square-bracketed capture clause, in which items are separated by commas. In C++17 we'll be able to use structured bindings:

for (const auto& [name, description] : planet_descriptions) {
    std::cout << "Planet " << name << ":\n" << description << "\n\n";
}

which is another example of a comma-separated square-bracketed clause.

Yet, we cannot override a class' operator[] to take several parameters, e.g. this:

template<typename V, typename I, typename J>
const V& operator[](I i, J j) const {
    return data_[width() * i + j];
}

will not compile.

I know there are workarounds - many are mentioned here:

C++ [] array operator with multiple arguments?

But - why are the former part of the language while the latter impossible even as an overload at the programmer's discretion? Is it simply because nobody has proposed otherwise, or is there some specific reason for it?

Notes:

  • Yes, of course this will create ambiguity / incompatibility with using the comma operator in a call to a unary operator[]: x[a, b] would be either operator[](operator,(a,b)) or operator[](a,b). However, we have sort-of the same ambiguity with round brackets: foo(a,b) might be a call to a binary foo() with a and b, or it might be foo(operator,(a,b). The language standard simply decrees it's the former rather than the latter (or that the former should be preferred); the same preference could be decreed for square brackets. In fact, if I'm not mistaken that will not actually break any existing code - since existing code won't have a binary operator[] to prefer.
  • The example binary operator[] is just an example, not something I want to implement.
Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 12
    `x[a, b]` already has a meaning in the existing syntax - it uses a comma operator. Changing this to mean something different might make existing code become ambiguous and fail to compile at best; or successfully compile but change semantics, at worst. – Igor Tandetnik May 06 '17 at 20:14
  • Just to throw it into the pot. There is the equivalence for *(p1 + i1), p1[i1], i1[p1]. This is not in line with what you are suggesting. – Captain Giraffe May 06 '17 at 20:16
  • @IgorTandetnik: Well, you have the same ambiguity with function calls: `foo(a,b)` might be "call a binary `foo()` with `a` and `b`" and also "call a unart `foo()` with `operator,(a,b)`". – einpoklum May 06 '17 at 20:17
  • 6
    I don't believe `foo(a,b)` is ever interpreted as using a comma operator under current grammar. Can you show an example? – Igor Tandetnik May 06 '17 at 20:19
  • @IgorTandetnik: I'm not saying that it's interpreted that way; but it _could_ be, in the sense that a function call takes expressions, and you can form an expression with `operator,`. – einpoklum May 06 '17 at 20:21
  • operator[] has absolutely nothing to do with the lambda capture syntax. It just happens to use some of the same characters. – juanchopanza May 06 '17 at 20:23
  • @juanchopanza: It does have something in common: The use of a comma-separated list of token sequences within square brackets... I wasn't suggesting that the semantics are related, just that WG21 is willing to utilize `[ , , , ]` lists in all sorts of places. – einpoklum May 06 '17 at 20:25
  • Oh, I must have gotten confused by "*Since C++11 we can write lambdas such as...*" and most of your question. Many things in C++ have commas. Why not talk about them too? – juanchopanza May 06 '17 at 20:27
  • Well, it couldn't be, in the current C++ grammar. Top-level commas inside parens that are part of a function call are always argument separators, never an application of a comma operator. Been this way from K&R (and possibly earlier). Not so with square brackets. – Igor Tandetnik May 06 '17 at 20:28
  • @juanchopanza: (1) Because they're not within square brackets. (2) Because these are prominent recent additions to the language which come to mind. – einpoklum May 06 '17 at 20:28
  • @IgorTandetnik: Yes, you are right. My question is whether has this been discussed and decided, or has there just never been another proposal. – einpoklum May 06 '17 at 20:29
  • 5
    So what if they are within square brackets? The brackets mean completely different things. – juanchopanza May 06 '17 at 20:31
  • @juanchopanza: So it's now common for square brackets to behave like round brackets, i.e. have comma-separated lists of things which are not applications of the comma operator to expressions. That suggests it should not be such a big no-no to pass multiple parameters to `operator[]` via square brackets. – einpoklum May 06 '17 at 21:38
  • There was never any technical limitation that stopped people from interpreting commas inside square brackets as the comma operator. It is simply the grammar that was chosen, which is constrained by how the access operator maps to pointer arithmetic. Nobody finally discovered a means to interpret commas otherwise in order to implement lambdas. They figured lambdas were be good to have in the language, and then they found a syntax for them. That syntax happened to employ square brackets and commas. It could have used `{}` or `||` instead. – juanchopanza May 06 '17 at 21:47
  • "that will not actually break any existing code" Seriously? That breaks all existing code that writes `a[b,c]` and expects the comma to be interpreted as the comma operator. – T.C. May 06 '17 at 22:47
  • @T.C.: No it wouldn't, since no existing code defines an `operator[]` taking two parameters. – einpoklum May 07 '17 at 00:20
  • So you want some crazy rule that tries to parse `a[b, c]` two ways? – T.C. May 07 '17 at 00:22
  • Besides, it is valid to make a `operator[]` that's a variadic template. While there's no real reason to do that now, that may well seem useful in your alternate world, and then how would your disambiguation work? – T.C. May 07 '17 at 00:26
  • @T.C.: You're opening an interesting discussion, but it's beyond the scope of comments on this question, I think. Also, you're coming off as a bit antagonistic. – einpoklum May 07 '17 at 00:31
  • I think your examples are of a somewhat different quality. In both lambdas and structured bindings, you're actually providing a sort-of name ("Some lambda of..." and "Some tuple/tie/structure thing of"), while the postfix [] is a postfix operator on a value. I think that the concept of "command-separated square-bracketed clause" is confusing the textual representation with semantics. – TBBle May 10 '17 at 13:18

1 Answers1

2

It's certainly an option, although surprising to many, given the general tendency to stick to C syntax for operators familiar to C programmers.

It's also not a new idea, Gabriel Dos Reis suggested it in 2014. The last-documented state of the idea from Uniform handling of operator[] and operator() is follows:

In c++std-core-14770, Dos Reis suggests that operator[] and operator() should both be allowed to be static. In addition to that, he suggests that both should allow multiple parameters. It's well known that there's a possibility that this breaks existing code (foo[1,2] is valid, the thing in brackets is a comma-expression) but there are possibilities to fix such cases (by requiring parens if a comma-expression is desired). EWG should discuss whether such unification is to be strived for.

Discussed in Rapperswil 2014. EWG points out that there are more issues to consider here, in terms of other operators, motivations, connections with captureless lambdas, who knows what else, so an analysis paper is requested.

So to paraphrase that eminent C++ language theorist: If you like it then write a paper on it.

TBBle
  • 1,436
  • 10
  • 27
  • Thank you for answering my question rather than going on a diatribe regarding why this may not be a good idea. I know the standard committee maintains an archive of papers, but are there minutes of those discussions anywhere? – einpoklum May 10 '17 at 13:35
  • I believe minutes of the WG21 meetings are not generally published. I understand that's an ISO rule... Apart from the comments on the defect reports themselves, your best bet is generally "trip reports" that are published by some attendees. The two I could turn up didn't seem to mention the discussion: https://botondballo.wordpress.com/2014/07/17/trip-report-c-standards-committee-meeting-in-rapperswil-june-2014/ and https://developers.redhat.com/blog/2014/08/21/iso-cxx-meeting-rapperswil-2014-core-library/ – TBBle May 10 '17 at 13:48
  • To correct myself: Minutes are taken and published, but they're of the whole-group stages, which appear to just be the first morning and last afternoon usually, e.g. [WG21 2017-02 Kona Minutes](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4654.pdf). 2017-02 Kona was particularly long because there was a lot of whole-group work in finalising C++17. A more-representative entry is probably [PL22.16 2016-11 Issaquah Minutes (final)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4634.pdf) which basically says nothing about what happened there. – TBBle May 11 '17 at 00:05
  • The ISO rule I was thinking of forbids *recording* meetings. Minutes are probably a formal *requirement*, in fact. – TBBle May 11 '17 at 00:06