Overloading operator[] for tuples.

709 views
Skip to first unread message

Germán Diago

unread,
Oct 18, 2015, 8:55:46 AM10/18/15
to ISO C++ Standard - Future Proposals
Hello everyone,

I started a proposal for using operator[] for std::tuple and, eventually, replace std::get<>.

My proposal is a draft for now and lives here:


Feedback is welcome.

Thanks for your time.

Nicol Bolas

unread,
Oct 18, 2015, 11:05:58 AM10/18/15
to ISO C++ Standard - Future Proposals
Assuming it actually works, I find your motivating example to not be very motivational. Here is your before&after:

//Before:
f
(std::get<0>(fib), std::get<1>(fib), std::get<2>(fib), std::get<3>(fib),
  std
::get<4>(fib));

//Now:
f
(fib[c<0>], fib[c<1>], fib[c<2>], fib[c<3>], fib[c<4>]);

This requires the creation of an ancillary type `c`, without which your code would look like this:

//Before:
f
(std::get<0>(fib), std::get<1>(fib), std::get<2>(fib), std::get<3>(fib),
  std
::get<4>(fib));

//Now:
f
(fib[std::integral_constant<size_t, 0>], fib[std::integral_constant<size_t, <1>], fib[std::integral_constant<size_t, <2>], fib[std::integral_constant<size_t, <3>], fib[std::integral_constant<size_t, <4>]);

Not so compact anymore, now is it? So, is `c` going to be part of the standard library? If not, then everyone's going to have to declare one to make this even usable.

And even if it is, what have you gained? Either everyone will use `std::c`, or they'll invoke `using std::c`. Which means that the appropriate comparison should be:

//Before:
f
(get<0>(fib), get<1>(fib), get<2>(fib), get<3>(fib), get<4>(fib));

//Now:
f
(fib[c<0>], fib[c<1>], fib[c<2>], fib[c<3>], fib[c<4>]);

After all, if I can do `using std::c`, I should be able to do `using std::get` too. Indeed, the latter is rather less likely to conflict with some local variable.

What is the advantage here? That it's a member function? Or is it the whole two characters we save in typing `[c<0>]` instead of `get<0>()`?

There's not much motivating this, as far as I can see.

Germán Diago

unread,
Oct 18, 2015, 11:12:20 AM10/18/15
to std-pr...@isocpp.org
2015-10-18 22:05 GMT+07:00 Nicol Bolas <jmck...@gmail.com>:

What is the advantage here? That it's a member function? Or is it the whole two characters we save in typing `[c<0>]` instead of `get<0>()`?

There's not much motivating this, as far as I can see.

One of the guidelines for C++ is to "make it easier to teach and learn". This proposal tries to unify the interface to something
that seems more natural to anyone. I admit you must introduce more things such as, maybe, user-defined literals.

I do think that doing this kind of polishing goes in the right direction, the same as introducing _t aliases and _v variable templates.
Maybe this is just my opinion, but I think that this points to the same direction: polishing.

Remember that not everyone is as used to C++ as people in this list, and std::get is unnecesarily a different interface for indexing.
I see that as a candidate for improving.

Thanks for your feedback. 

Nicol Bolas

unread,
Oct 18, 2015, 1:05:15 PM10/18/15
to ISO C++ Standard - Future Proposals


On Sunday, October 18, 2015 at 11:12:20 AM UTC-4, Germán Diago wrote:


2015-10-18 22:05 GMT+07:00 Nicol Bolas <jmck...@gmail.com>:

What is the advantage here? That it's a member function? Or is it the whole two characters we save in typing `[c<0>]` instead of `get<0>()`?

There's not much motivating this, as far as I can see.

One of the guidelines for C++ is to "make it easier to teach and learn". This proposal tries to unify the interface to something
that seems more natural to anyone.

Modern C++ tends to be moving away from member functions, not towards them. What "seems more natural" depends entirely on what you've been taught. Former Java programmers tend to see non-member functions as very unnatural. C++ programmers raised on std::begin/end and so forth, are likely more willing to see them as simply a part of the interface.

This will only increase with concepts and other upcoming C++ features. And unified function syntax is on the cusp of making the distinction more or less moot, allowing users to just say `t.get<0>()` (though that's in jeopardy. Thanks, two-phase lookup).

I think new users would be better served by not being trained to think of member functions as the only "natural" interface for a type. And `get`'s design reinforces that.
 
Remember that not everyone is as used to C++ as people in this list, and std::get is unnecesarily a different interface for indexing.
I see that as a candidate for improving.

Then again, people who are not "as used to C++" are probably not using `tuple` at all. The primary uses for tuples are:

1) multiple return values. Not exactly common among neophytes.

2) template metaprogramming tools. Definitely not common among neophytes.

Klemens Morgenstern

unread,
Oct 18, 2015, 1:56:10 PM10/18/15
to ISO C++ Standard - Future Proposals
I think the reason for having a tuple-getter as a non-member function is, that it produces less code, but I might be wrong with that.


The problem I see is, that the behaviours is utterly inconsistent with other standard types. So you expect the operator[] to always return the same type and you expect std::get to give different types. Not an std::array can be used as a tuple of the same type and as an container. Hence you have std::get to get the element and you have operator[].

Now if you want to have it consistent, you should be able to do basicly everything with a tuple, which you could also do with a container. This can become possible with std::variant, but for now it's not. If we have std::variant, we could propose to make the container concept more general.

Thiago Macieira

unread,
Oct 18, 2015, 3:33:06 PM10/18/15
to std-pr...@isocpp.org
On Sunday 18 October 2015 10:05:15 Nicol Bolas wrote:
> Modern C++ tends to be moving *away* from member functions, not towards
> them

s/Modern C++/Modern Standard Library/

That is definitely not the trend in C++ other libraries.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Germán Diago

unread,
Oct 18, 2015, 8:23:09 PM10/18/15
to ISO C++ Standard - Future Proposals


The problem I see is, that the behaviours is utterly inconsistent with other standard types.
 
So you expect the operator[] to always return the same type.
 
II tend to look at this as indexing an ordered sequence. Makes sense. Why should the type be the same?

Now if you want to have it consistent, you should be able to do basicly everything with a tuple, which you could also do with a container.

I do not pretend a tuple is a container, but, still, indexing is a minimum expectation. I think the first thing a newcomer to C++ 
would expect from a tuple is to be able to index them. Are iterators even possible? Maybe I should try some experiments,
but those would not work wwith the stl due to being heterogeneous.
 
 

Nicol Bolas

unread,
Oct 18, 2015, 9:02:58 PM10/18/15
to ISO C++ Standard - Future Proposals
On Sunday, October 18, 2015 at 8:23:09 PM UTC-4, Germán Diago wrote:
The problem I see is, that the behaviours is utterly inconsistent with other standard types.
 
So you expect the operator[] to always return the same type.
 
II tend to look at this as indexing an ordered sequence. Makes sense. Why should the type be the same?

Because pretty much every other index-able class returns the same type from its operator[].

Now if you want to have it consistent, you should be able to do basicly everything with a tuple, which you could also do with a container.

I do not pretend a tuple is a container, but, still, indexing is a minimum expectation.

A minimum expectation from whom?

If you look around, indexing is typically something you do to containers (usually contiguous) or views thereof. So your argument seems self-refuting: if users aren't supposed to see a tuple as a container, then they aren't going to expect to be able to index it.

I think the first thing a newcomer to C++ 
would expect from a tuple is to be able to index them.

A newcomer from some other language with native tuples? Possibly. But from other near-C++ languages (like Java or C#, neither of which have [] indexing), or simply neophyte programmers? Their first question will be... what's a tuple?

And from the description, I doubt they'll expect to be able to index it.

However, let's say that "a newcomer to C++" would indeed expect a tuple to be indexable. Would they not also expect it to be indexable with an integer, not some funny integral_constant thing? A newcomer who didn't understand much about the language would be non-plussed to learn that this simple loop isn't possible:

for(int x : irange(0, tpl.count()))
{
 
auto &value = tpl[x];
}

They can't even do `tpl[c<x>()]`, which to a newbie makes perfect sense. The compiler will give them some funny error they don't understand.

If we're going to start speculating about what newcomers would expect, I think it's just as reasonable to think that, if you give them indexing, they'll expect integer indexing. At least with `std::get`, the interface is so different that there is less of a surprise when `get<x>` errors out.

Are iterators even possible?

Look at Boost.Fusion.

Now, those won't be STL iterators. But they serve the purpose of an iterator, and they do work in (meta)algorithms.

Germán Diago

unread,
Oct 18, 2015, 9:46:07 PM10/18/15
to ISO C++ Standard - Future Proposals


El lunes, 19 de octubre de 2015, 8:02:58 (UTC+7), Nicol Bolas escribió:
On Sunday, October 18, 2015 at 8:23:09 PM UTC-4, Germán Diago wrote:
The problem I see is, that the behaviours is utterly inconsistent with other standard types.
 
So you expect the operator[] to always return the same type.
 
II tend to look at this as indexing an ordered sequence. Makes sense. Why should the type be the same?

Because pretty much every other index-able class returns the same type from its operator[]. 

Now if you want to have it consistent, you should be able to do basicly everything with a tuple, which you could also do with a container.

I do not pretend a tuple is a container, but, still, indexing is a minimum expectation.

A minimum expectation from whom?

Well, D can index tuples and they are the same as in C++. I do not know of another language closest to C++ than D.
But the point is that it is easy to guess how to index a tuple. This is just an opinion, maybe.
 

If you look around, indexing is typically something you do to containers (usually contiguous) or views thereof. So your argument seems self-refuting: if users aren't supposed to see a tuple as a container, then they aren't going to expect to be able to index it.

Well, that a tuple is not a container does not mean we do not index access: we usually refer to first element, second, third, of a sequence of ordered types.
It is natural to map that to index, and not to a "special-case" provided std::get. But this is open to opinion actually. I just see that it is one less rule/function to remember:
want to access nth element of something? use operator[]. Want to access key of an associative container? Use operator[] (most of the time, I know the limitations).
 

I think the first thing a newcomer to C++ 
would expect from a tuple is to be able to index them.

A newcomer from some other language with native tuples? Possibly. But from other near-C++ languages (like Java or C#, neither of which have [] indexing), or simply neophyte programmers? Their first question will be... what's a tuple?

D has tuples with index access.
 

And from the description, I doubt they'll expect to be able to index it.

However, let's say that "a newcomer to C++" would indeed expect a tuple to be indexable. Would they not also expect it to be indexable with an integer, not some funny integral_constant thing? A newcomer who didn't understand much about the language would be non-plussed to learn that this simple loop isn't possible:

for(int x : irange(0, tpl.count()))
{
 
auto &value = tpl[x];
}

You can also do that in D and it is nice compile-time expansion. Actually I have also been thinking of how to do this.
All of this comes from my impression that in D it is easier to write code, especially with compile-time expansion and index for tuples and a
few other niceties. However, D is not C++ and I cannot replace it for most uses.

 
They can't even do `tpl[c<x>()]`, which to a newbie makes perfect sense. The compiler will give them some funny error they don't understand.

If we're going to start speculating about what newcomers would expect, I think it's just as reasonable to think that, if you give them indexing, they'll expect integer indexing. At least with `std::get`, the interface is so different that there is less of a surprise when `get<x>` errors out.

Well, go to 20 people that have used C++ only for some weeks. Ask them: how would you access the nth element of a tuple? How many do you think would say operator[],
and how many std::get (which maybe they do not even know). My bet is on operator[]. And it is still integer access, just that needs compile-time deduction, hence,
std::integer_constant is what we need. That is what Boost.Hana proposes, and I see it reasonable and readable.
 

Are iterators even possible?

Look at Boost.Fusion.

Now, those won't be STL iterators. But they serve the purpose of an iterator, and they do work in (meta)algorithms.

Something to look into, thank you. :) 

Evgeny Panasyuk

unread,
Oct 18, 2015, 9:59:33 PM10/18/15
to std-pr...@isocpp.org
19.10.2015 3:23, Germán Diago:
> Are iterators
> even possible? Maybe I should try some experiments,
> but those would not work wwith the stl due to being heterogeneous.


Iterators are possible, but special ones. Boost.Fusion already
implements heterogeneous iterators, containers, algorithms, views, etc.
For instance:
http://www.boost.org/doc/libs/1_59_0/libs/fusion/doc/html/fusion/iterator/concepts/forward_iterator.html

Evgeny Panasyuk

unread,
Oct 18, 2015, 10:15:07 PM10/18/15
to ISO C++ Standard - Future Proposals
18 2015 г., 18:12:20 UTC+3 Germán Diago:

Remember that not everyone is as used to C++ as people in this list, and std::get is unnecesarily a different interface for indexing.
I see that as a candidate for improving.

In my opinion, std::get is the most natural thing for this task.
We have tuple and compile-time number, and we should pass them into one function somehow in order to get result. Compile-time things in C++ are passed as template parameters, runtime - via "normal" parameters. Non-member functions are preferred to member-functions. As the result answer is:
some_function_template<index>(tup)
i
.e.
get<index>(tup)

And by the way, tuples should not be very common in user code. They are abused for multiple return values, but I think in such cases it is much better to define just struct with good named fields. Or, if you want to do everything "within" function definition, you could use:
auto foo()
{
   
struct
   
{
       
int value;
       
double x;
   
} result = {1, 0.5};
   
return result;
}

Or, with help of macro, it could be:
auto foo()
{
   
return NEW((value, 1)(x, 0.5));
}

Nicol Bolas

unread,
Oct 18, 2015, 11:39:44 PM10/18/15
to ISO C++ Standard - Future Proposals
On Sunday, October 18, 2015 at 9:46:07 PM UTC-4, Germán Diago wrote:
El lunes, 19 de octubre de 2015, 8:02:58 (UTC+7), Nicol Bolas escribió:
On Sunday, October 18, 2015 at 8:23:09 PM UTC-4, Germán Diago wrote:
 
It is natural to map that to index, and not to a "special-case" provided std::get. But this is open to opinion actually. I just see that it is one less rule/function to remember:
want to access nth element of something? use operator[]. Want to access key of an associative container? Use operator[] (most of the time, I know the limitations).

std::set and its variations don't overload operator[]. Neither does std::list.

So it would seem that `operator[]` is not nearly as ubiquitous as you claim. If a user wants the second value in a `list`, they can't use `operator[]` for that.
 
They can't even do `tpl[c<x>()]`, which to a newbie makes perfect sense. The compiler will give them some funny error they don't understand.

If we're going to start speculating about what newcomers would expect, I think it's just as reasonable to think that, if you give them indexing, they'll expect integer indexing. At least with `std::get`, the interface is so different that there is less of a surprise when `get<x>` errors out.

Well, go to 20 people that have used C++ only for some weeks. Ask them: how would you access the nth element of a tuple? How many do you think would say operator[],
and how many std::get (which maybe they do not even know).

Neither. They'll ask what a tuple is.

My bet is on operator[].

You'd be wrong, because none of them even know what `operator[]` is. They might say that you use `[]` notation, but they certainly would know nothing of operator overloading.

So they're not going to say "use operator[]". They're going to say `tuple[4]`. Which you cannot in your proposal. They would be no more correct under your proposal than they would be under the current paradigm.

If C++ gets the ability to use regular old integer variables with tuple access, I'd be more willing to see operator[] work on it. But unless `operator[]` is going to behave like regular `operator[]` overloads (ie: operating on seemingly runtime values), then I don't see the point. If retrieving elements of a tuple has to be done using different syntax from other types, I'd rather that the syntax be very different.

And it is still integer access, just that needs compile-time deduction, hence,
std::integer_constant is what we need.

And you think that's a concept which C++ programmers who've been writing code for "a few weeks" ought to be introduced to?

Giovanni Piero Deretta

unread,
Oct 19, 2015, 6:00:28 AM10/19/15
to ISO C++ Standard - Future Proposals

All comments so far have been negative. I would like to speak in favor for this proposal instead. I hate having to write std::get<N>(tuple) all the time.
Just a few suggestions:

* consider having 1st, 2nd, <N>th as literals for integral types.
* '3rd(tuple)' should be an option.
* with dot operator overloading we could have the nice "tuple.3rd" syntax instead (I do not think it is supported with any of the current overloading proposals, but it would be nice to have. Aliasing 'first' and 'second' to 1st and 2nd to make tuples fully interface compatible with pairs.

Germán Diago

unread,
Oct 19, 2015, 8:20:15 AM10/19/15
to ISO C++ Standard - Future Proposals


El lunes, 19 de octubre de 2015, 10:39:44 (UTC+7), Nicol Bolas escribió:
On Sunday, October 18, 2015 at 9:46:07 PM UTC-4, Germán Diago wrote:
El lunes, 19 de octubre de 2015, 8:02:58 (UTC+7), Nicol Bolas escribió:
On Sunday, October 18, 2015 at 8:23:09 PM UTC-4, Germán Diago wrote:
 
It is natural to map that to index, and not to a "special-case" provided std::get. But this is open to opinion actually. I just see that it is one less rule/function to remember:
want to access nth element of something? use operator[]. Want to access key of an associative container? Use operator[] (most of the time, I know the limitations).

std::set and its variations don't overload operator[]. Neither does std::list.

I start to find these arguments too weak. std::list has O(n) access for that. std::set is not associative. std::tuple is supposed to be constant time access, at least at run-time,
because everything is solved at compile-time :)
 

So it would seem that `operator[]` is not nearly as ubiquitous as you claim. If a user wants the second value in a `list`, they can't use `operator[]` for that. 
 
They can't even do `tpl[c<x>()]`, which to a newbie makes perfect sense. The compiler will give them some funny error they don't understand.

If we're going to start speculating about what newcomers would expect, I think it's just as reasonable to think that, if you give them indexing, they'll expect integer indexing. At least with `std::get`, the interface is so different that there is less of a surprise when `get<x>` errors out.


You have to compare alternatives: operator[] vs std::get<N>. Now your requirement is a *plain* integer. Just cause you said so, right? I would laugh if it were funny,
but I find the operator[] interface easier to teach, and I think it should be part of the core of a std::tuple. 
By the way, if operator[] must be a member function, I think this is also something that should be fixed, maybe when we get uniform call syntax.

 
Well, go to 20 people that have used C++ only for some weeks. Ask them: how would you access the nth element of a tuple? How many do you think would say operator[],
and how many std::get (which maybe they do not even know).

Neither. They'll ask what a tuple is.

 
My bet is on operator[].

You'd be wrong, because none of them even know what `operator[]` is. They might say that you use `[]` notation, but they certainly would know nothing of operator overloading.
 
What syntax they would look for if they have a Python background, a D background, for example. Or C background. They would synthetize std::get<N> in their heads
and guess? Or they would say: oh, this is indexing. Indexing was this [] thing, right? Maybe you do not find value in this, but I do find it more natural and less 
surprising to newcomers, hence, easier to teach.


So they're not going to say "use operator[]". They're going to say `tuple[4]`. Which you cannot in your proposal. They would be no more correct under your proposal than they would be under the current paradigm.

tuple[4] vs tuple[4is] --- is there really a huge difference? Is std::get<> better? Why? 

 
If C++ gets the ability to use regular old integer variables with tuple access, I'd be more willing to see operator[] work on it. But unless `operator[]` is going to behave like regular `operator[]` overloads (ie: operating on seemingly runtime values), then I don't see the point. If retrieving elements of a tuple has to be done using different syntax from other types, I'd rather that the syntax be very different.

Cannot be done, but that proposal is pretty close to that ideal and is more uniform than having std::get<N>.
 

And it is still integer access, just that needs compile-time deduction, hence,
std::integer_constant is what we need.

And you think that's a concept which C++ programmers who've been writing code for "a few weeks" ought to be introduced to?

As an alternative to what you say: Is std::get<N>(t)  template access newcomer-friendly to explain? No. 

What is easier to teach?

1. People know operator[] and they are taught about tuples. For tuples you teach them: tuple[1is]. (Rule is: put number, add is)
OR
2. You teach them about function std::get<N>, which has a totally different interface, and start to tell them about passing a number in between that strange <> sign.

Come on, be honest, which one is easier to teach how to use? I am not talking about the implementation. Both are hairy.

Greg Marr

unread,
Oct 19, 2015, 10:29:56 AM10/19/15
to ISO C++ Standard - Future Proposals
On Monday, October 19, 2015 at 8:20:15 AM UTC-4, Germán Diago wrote:
As an alternative to what you say: Is std::get<N>(t)  template access newcomer-friendly to explain? No. 

What is easier to teach?

1. People know operator[] and they are taught about tuples. For tuples you teach them: tuple[1is]. (Rule is: put number, add is)
OR
2. You teach them about function std::get<N>, which has a totally different interface, and start to tell them about passing a number in between that strange <> sign.
 
If they're still thinking "that strange <> sign" in std::get<3>(), then what are they going to think about something like std::tuple<int, std::vector<std::string>, std::complex<double>>? If you can teach them about using tuple[1is] to access the first type, it means that that they've already been taught about "that strange <> sign", otherwise they have no idea what the first type of a tuple is.

Matthew Woehlke

unread,
Oct 19, 2015, 11:39:19 AM10/19/15
to std-pr...@isocpp.org
On 2015-10-18 23:39, Nicol Bolas wrote:
> If C++ gets the ability to use regular old integer variables with tuple
> access, I'd be more willing to see operator[] work on it. But unless
> `operator[]` is going to behave like regular `operator[]` overloads (ie:
> operating on seemingly runtime values), then I don't see the point.

I would remove "seemingly" from that. It ought to *work* on runtime
values, period. (That does imply that it would have to return std::any /
std::variant...)

--
Matthew

Nicol Bolas

unread,
Oct 19, 2015, 11:55:43 AM10/19/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com

Now that? That's an idea.

I'd prefer `variant` over than `any` as the return type of such a function (with the order defined as the exact order of types in the `tuple`). Indeed, I think this should be added to `variant` proposals.

Using operator[] and a visitor to iterate over a tuple's elements at runtime would be a very nifty thing indeed.

In fact, such a runtime operator[] would provide a good reason to provide a static version. For the sake of orthogonality.

Nicol Bolas

unread,
Oct 19, 2015, 11:56:15 AM10/19/15
to ISO C++ Standard - Future Proposals

That's generally my point. Maybe if you're writing Python or D, tuples are a week 5 lesson. But in C++, you don't touch tuples for rather longer than that. Or at least, not seriously.

You might introduce them to `std::tie` for returning multiple values fairly early on. But you wouldn't be showing them `get<>` for quite some time.

Johannes Schaub

unread,
Oct 19, 2015, 11:59:08 AM10/19/15
to std-pr...@isocpp.org

+1 for op[] with variant returns in the order of the tuple. That's cool.

Can a variant store references?

> --
>
> ---
> You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

Nicol Bolas

unread,
Oct 19, 2015, 12:09:40 PM10/19/15
to ISO C++ Standard - Future Proposals
On Monday, October 19, 2015 at 8:20:15 AM UTC-4, Germán Diago wrote:
El lunes, 19 de octubre de 2015, 10:39:44 (UTC+7), Nicol Bolas escribió:
On Sunday, October 18, 2015 at 9:46:07 PM UTC-4, Germán Diago wrote:
El lunes, 19 de octubre de 2015, 8:02:58 (UTC+7), Nicol Bolas escribió:
On Sunday, October 18, 2015 at 8:23:09 PM UTC-4, Germán Diago wrote:
 
It is natural to map that to index, and not to a "special-case" provided std::get. But this is open to opinion actually. I just see that it is one less rule/function to remember:
want to access nth element of something? use operator[]. Want to access key of an associative container? Use operator[] (most of the time, I know the limitations).

std::set and its variations don't overload operator[]. Neither does std::list.

I start to find these arguments too weak. std::list has O(n) access for that. std::set is not associative.

The C++ standard disagrees with you. 23.4 is called "Associative containers". And it contains `set`. The concept for "associative container" is filled by `set`.

Ergo `set` is an associative container. And it has no operator[]. Thus, your statement that you use operator[] on associative containers is wrong.
 
They can't even do `tpl[c<x>()]`, which to a newbie makes perfect sense. The compiler will give them some funny error they don't understand.

If we're going to start speculating about what newcomers would expect, I think it's just as reasonable to think that, if you give them indexing, they'll expect integer indexing. At least with `std::get`, the interface is so different that there is less of a surprise when `get<x>` errors out.


You have to compare alternatives: operator[] vs std::get<N>. Now your requirement is a *plain* integer. Just cause you said so, right?

You provide no evidence for your claim that operator[] is easier to teach. So I see no problem making unsupported claims of my own that such people would expect to use an integer variable in [].

So they're not going to say "use operator[]". They're going to say `tuple[4]`. Which you cannot in your proposal. They would be no more correct under your proposal than they would be under the current paradigm.

tuple[4] vs tuple[4is] --- is there really a huge difference?

Yes. At the very least, 4is requires importing the namespace that includes the "is" literal. Not to mention, you're arguing "teachability". Well, they have to learn to import that namespace and use the `is` suffix. And to always use literals.

That's a pretty big difference from `tuple[4]`.
 
Is std::get<> better? Why?

I never claimed it was necessarily "better".

Look, if this were 2009 and we were debating including tuple in the standard, I might agree with your position. However, this is 2015. Tuple is done, there, and has been for 4 years.

To add a new interface to do the same thing, now? All for supposed "teachability"? No. You're going to need more of a motivation than that to add a redundant interface.
 
And it is still integer access, just that needs compile-time deduction, hence,
std::integer_constant is what we need.

And you think that's a concept which C++ programmers who've been writing code for "a few weeks" ought to be introduced to?

As an alternative to what you say: Is std::get<N>(t)  template access newcomer-friendly to explain? No. 

What is easier to teach?

1. People know operator[] and they are taught about tuples. For tuples you teach them: tuple[1is]. (Rule is: put number, add is)

Don't forget the `using namespace` you need to use that literal.
 
OR
2. You teach them about function std::get<N>, which has a totally different interface, and start to tell them about passing a number in between that strange <> sign.

Others have pointed out that the whole "strange <> sign" is fundamentally wrong, since they have to have seen that already.

To me, neither is more "teachable" than the other. `tuple` is just not a newbie-programmer type.

Nicol Bolas

unread,
Oct 19, 2015, 12:19:19 PM10/19/15
to ISO C++ Standard - Future Proposals
On Monday, October 19, 2015 at 11:59:08 AM UTC-4, Johannes Schaub wrote:

+1 for op[] with variant returns in the order of the tuple. That's cool.

Can a variant store references?


N4542 says that it can. But you can't assign to a reference, you can only initialize to it. Which should be sufficient. As long as the reference doesn't inhibit copy/movement, it ought to be fine.

Nevin Liber

unread,
Oct 19, 2015, 12:21:53 PM10/19/15
to std-pr...@isocpp.org
On 19 October 2015 at 10:59, 'Johannes Schaub' via ISO C++ Standard - Future Proposals <std-pr...@isocpp.org> wrote:

+1 for op[] with variant returns in the order of the tuple. That's cool.

I must be missing the point of doing this.  Why would I want to copy each of the members out of the tuple into a variant, as opposed to just having a visitor visit every element in the tuple?

Can a variant store references?

Maybe we'll find out this week... :-) 
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Matthew Woehlke

unread,
Oct 19, 2015, 12:36:34 PM10/19/15
to std-pr...@isocpp.org
On 2015-10-19 12:09, Nicol Bolas wrote:
> On Monday, October 19, 2015 at 8:20:15 AM UTC-4, Germán Diago wrote:
>> I start to find these arguments too weak. std::list has O(n) access for
>> that. std::set is not associative.
>
> The C++ standard disagrees with you. 23.4 is called "Associative
> containers". And it contains `set`. The concept for "associative container
> <http://en.cppreference.com/w/cpp/concept/AssociativeContainer>" is filled
> by `set`.
>
> Ergo `set` is an associative container. And it has no operator[]. Thus,
> your statement that you use operator[] on associative containers is wrong.

std::set is... weird. It is an associative container that has keys, but
no values. There is no more technical reason for it to omit operator[]
than for std::map to omit operator[]. More likely, the reason it has no
operator[] is because a) it would be redundant with the insert() method,
and b) it would not return a value, which would be very peculiar for an
operator[].

The reason for std::tuple to not have an operator[] is not entirely
dissimilar; the return value is necessarily exotic in some fashion.
Either it is a "strange" type (std::any or std::variant), or it is
highly sensitive to overload resolution (which, as with having no return
value at all, would be novel for an operator[]).

(The first of those I can see being overcome by the utility of being
able to index a tuple with a runtime index. The second is distinctly
lacking in meaningful advantage.)

--
Matthew

Jakob Riedle

unread,
Nov 6, 2015, 9:45:24 AM11/6/15
to ISO C++ Standard - Future Proposals
Is there any problem with writing it this way?

auto operator[]( constexpr int idx ) -> decltype(std::tuple_element<idx,T>::type){
 
return std::get<idx>(*this);
}

I hope I did not miss some part of the conversation that said something about this solution.
Yours,
Jakob

Sam Kellett

unread,
Nov 6, 2015, 11:27:13 AM11/6/15
to std-pr...@isocpp.org
won't compile as you can't have constexpr parameters. it's explained well here:
http://boostorg.github.io/hana/index.html#tutorial-appendix-constexpr

hana also has an implementation of the [] operator for tuple's that does work which is very similar to yours:

  template <typename N>
  constexpr decltype(auto) operator[](N const&) {
     return std::get<N::value>(*this);
  }
 
taken from here: http://boostorg.github.io/hana/index.html#tutorial-integral-more

Vicente J. Botet Escriba

unread,
Nov 6, 2015, 11:49:54 AM11/6/15
to std-pr...@isocpp.org
Le 19/10/15 12:00, Giovanni Piero Deretta a écrit :
> On Sunday, October 18, 2015 at 1:55:46 PM UTC+1, Germán Diago wrote:
>> Hello everyone,
>>
>> I started a proposal for using operator[] for std::tuple and, eventually,
>> replace std::get<>.
>>
>> My proposal is a draft for now and lives here:
>>
>> https://github.com/germandiagogomez/tup-op-brackets
>>
>> Feedback is welcome.
>>
>> Thanks for your time.
>>
> All comments so far have been negative.
As often, isn't it?
> I would like to speak in favor for
> this proposal instead. I hate having to write std::get<N>(tuple) all the
> time.
> Just a few suggestions:
>
> * consider having 1st, 2nd, <N>th as literals for integral types.
+1
> * '3rd(tuple)' should be an option.
So the 3rd should be a function object isn't it?

* tuple[3rd] is already quite readable.
> * with dot operator overloading we could have the nice "tuple.3rd" syntax
> instead (I do not think it is supported with any of the current overloading
> proposals, but it would be nice to have. Aliasing 'first' and 'second' to
> 1st and 2nd to make tuples fully interface compatible with pairs.
>
Well, we don't have them yet. Maybe this will add some ambiguity. Let
see when the proposal will be there.

Vicente

Vicente J. Botet Escriba

unread,
Nov 6, 2015, 11:53:46 AM11/6/15
to std-pr...@isocpp.org
Le 19/10/15 17:59, 'Johannes Schaub' via ISO C++ Standard - Future
Proposals a écrit :
> +1 for op[] with variant returns in the order of the tuple. That's cool.
The access must return a reference as get does. You can always store it
in a variant if you want.

Vicente

ga...@approachfoundation.org

unread,
Nov 6, 2015, 3:36:31 PM11/6/15
to ISO C++ Standard - Future Proposals
On Sunday, October 18, 2015 at 7:02:58 PM UTC-6, Nicol Bolas wrote:On Sunday, October 18, 2015 at 8:23:09 PM UTC-4, Germán Diago wrote:
The problem I see is, that the behaviours is utterly inconsistent with other standard types.
 
So you expect the operator[] to always return the same type.
 
 II tend to look at this as indexing an ordered sequence. Makes sense. Why should the type be the same?

Because pretty much every other index-able class returns the same type from its operator[].

Tuple is a unique and recent feature that is rather different from most existing features. The closest pre-existing features are std::pair and structs. There's nothing strange about equipping pairs with these operators, that'd be rather useful actually. On the other hand iterating through a struct would be quite a hassle. Especially, operator-based element access for tuple values is natural given the role tuples fill in a language that already had pair<int,pair<int,..>> and structs.

A minimum expectation from whom?
...

I think the first thing a newcomer to C++ 
would expect from a tuple is to be able to index them.

A newcomer from some other language with native tuples? Possibly. But from other near-C++ languages (like Java or C#, neither of which have [] indexing), or simply neophyte programmers? Their first question will be... what's a tuple?

And from the description, I doubt they'll expect to be able to index it.

Tuples were brought in to fill blanks common to many higher level languages. The ability to using container operators on serialized, multi-type sets is idiomatic in the languages that have been addressing the usage patterns longer than C++ users. We should nod to their wisdom on the matter.




They can't even do `tpl[c<x>()]`, which to a newbie makes perfect sense. The compiler will give them some funny error they don't understand.

If we're going to start speculating about what newcomers would expect, I think it's just as reasonable to think that, if you give them indexing, they'll expect integer indexing. At least with `std::get`, the interface is so different that there is less of a surprise when `get<x>` errors out.

Now that I do agree with. We can alter the implementation a little bit to allow both integer access and std iterator.

 

ga...@approachfoundation.org

unread,
Nov 6, 2015, 3:41:20 PM11/6/15
to ISO C++ Standard - Future Proposals

 
If C++ gets the ability to use regular old integer variables with tuple access, I'd be more willing to see operator[] work on it. But unless `operator[]` is going to behave like regular `operator[]` overloads (ie: operating on seemingly runtime values), then I don't see the point. If retrieving elements of a tuple has to be done using different syntax from other types, I'd rather that the syntax be very different.

Cannot be done, but that proposal is pretty close to that ideal and is more uniform than having std::get<N>.

Has been done using templates
Reply all
Reply to author
Forward
0 new messages