Sugar fix: static subscript operators

167 views
Skip to first unread message

mihailn...@gmail.com

unread,
Oct 20, 2016, 11:37:05 AM10/20/16
to ISO C++ Standard - Future Proposals
Right now to access the new types like tuple and variant, types without named fields, we use the rather awkward std::get<> syntax.

To the user perspective, this is nothing more then an index into the type, made in compile time.

In the light of the new structured bindings and the syntax sure there, can we improve this access as well?

Wouldn't it be nice instead of

std::tuple<int, string> tup;

std
::get<0>(tup) = 12;
std
::get<string>(tup) = "hello";

To say

tup.[0] = 12;
tup
.[string] = 12;

The idea being, a dot, as we would do with struct, but because of lack of name, we use a subscript operator syntax instead, thus becoming "static subscript operator".

I don't know if this is possible, just pointing it out as the "most logical" and "simplest" extension.
I also know, square braces have been overused lately...


This should work with pointers as well, though a bit more cumbersome.

(&tup)->[int] = 12;

The idea is to also be able to implement std::get_if with something in the lines of

std::variant<int, string> var;

if(auto v = (&var)->?[int]) //< same as std::get_if<int>(&var);
  std
::cout << "we have int: " << *v << '\n';


Anyways.
Just few ideas.

I wonder if there is any work in that direction?
I know there is work on getting variant with fields as native type.
But adding this will be beneficial nevertheless, I think.

Jens Maurer

unread,
Oct 20, 2016, 5:38:31 PM10/20/16
to std-pr...@isocpp.org
On 10/20/2016 05:37 PM, mihailn...@gmail.com wrote:
> Wouldn't it be nice instead of
>
> ||
> std::tuple<int,string>tup;
>
> std::get<0>(tup)=12;
> std::get<string>(tup)="hello";**//___^
>
> To say
>
> ||
> tup.[0]=12;
> tup.[string]=12;**//___^
> **

> I wonder if there is any work in that direction?

Not that I'm aware of.

If you want to have this happen, the first step is to write
a paper showing the necessary grammar changes and the
"translation" into std::get<> (or whatever) that you want
to see. This at least ensures it gets attention in the C++
committee's Evolution Working Group. I can't say whether
people will like it enough to buy into the grammar change.

If you need help obtaining a paper number and submitting it
for a committee mailing, send me e-mail.

Jens

Bengt Gustafsson

unread,
Oct 20, 2016, 6:23:33 PM10/20/16
to ISO C++ Standard - Future Proposals
I think this would be best solved by a more or less regular operator[] but with a constexpr parameter:

In tuple's class head:

   auto& operator[](constexpr size_t ix) { return std::get<ix>(*this); }

You get the drift. The idea of allowing a constexpr function parameter which is defined to be the equivalent of a template with a non-type template parameter was posted here a while ago. So the above would be equivalent of:

   template<size_t ix> auto& operator[]() { return std::get<ix>(*this); }

with two exceptions: 1: You can't make an operator[] without parameter, 2: you would not have to type the template keyword when calling the operator (or else the idea is moot).

With this you would obviously not have to add the dot before the [ as it is just a regular operator[] syntaxwise.

mihailn...@gmail.com

unread,
Oct 21, 2016, 2:39:06 AM10/21/16
to ISO C++ Standard - Future Proposals


On Friday, October 21, 2016 at 1:23:33 AM UTC+3, Bengt Gustafsson wrote:
I think this would be best solved by a more or less regular operator[] but with a constexpr parameter:

...
 
I am not sure if this wouldn't add parsing ambiguity at some places. Also, this makes tuple and variant look like an array in code, this might or might not be a problem.

Lastly, the operator should be free standing, much like get, so it can specialized, potentially even for regular struct, creating universal syntax.
This way a tuple can be "upgraded" to a struct and all instances will still work. On need-to bases one ca start using the field name for clarity.
This is also one bonuses to have a dot before the bracket - it makes it more easily searchable - ".[" is a unique construct.

I don't have strong opinion on any of these, because, this is just an idea.

mihailn...@gmail.com

unread,
Oct 22, 2016, 9:34:41 AM10/22/16
to ISO C++ Standard - Future Proposals, mihailn...@gmail.com


On Friday, October 21, 2016 at 9:39:06 AM UTC+3, mihailn...@gmail.com wrote:
... 
I am not sure if this wouldn't add parsing ambiguity at some places. Also, this makes tuple and variant look like an array in code, this might or might not be a problem.

Lastly, the operator should be free standing, much like get, so it can specialized, potentially even for regular struct, creating universal syntax.
This way a tuple can be "upgraded" to a struct and all instances will still work. On need-to bases one ca start using the field name for clarity.
This is also one bonuses to have a dot before the bracket - it makes it more easily searchable - ".[" is a unique construct.

...

Actually, having the dot is important so there can be an orthogonal arrow version for pointers.
Also, any future "operator dot" overloading should work (I guess). 
However, an "operator dot" overloading will probably create problems, because there are no names to pick the correct overload.
Am not sure about the alternative "op dot" proposals though.

mihailn...@gmail.com

unread,
Oct 23, 2016, 7:59:47 AM10/23/16
to ISO C++ Standard - Future Proposals, mihailn...@gmail.com
Just one motivating example

    struct Struct
    {
      string s = "hi";
      bool b {};       
      std::pair<Union, Union> pr;

      Struct() { pr.first.s = "lol"; pr.second.i = 1; }
    } stct;
    
    std::tuple<string, bool, tuple<variant<int, string>, variant<int, string>>> tup = { "hi", {}, { "lol", 1} };
    

    auto lol1 = stct.pr.first.s; //< natural access order, digging deeper into the struct
    
    auto lol2 = get<string>(get<0>(get<2>(tup))); //< reversed access, also, welcome to hell
    
    auto lol3 = tup.[2].[0].[string]; //< natural access order again
   

Granted, a universal call syntax would render this example much less attractive.



Vicente J. Botet Escriba

unread,
Oct 23, 2016, 1:32:00 PM10/23/16
to std-pr...@isocpp.org, mihailn...@gmail.com
Le 23/10/2016 à 13:59, mihailn...@gmail.com a écrit :
Just one motivating example

    struct Struct
    {
      string s = "hi";
      bool b {};       
      std::pair<Union, Union> pr;

      Struct() { pr.first.s = "lol"; pr.second.i = 1; }
    } stct;
    
    std::tuple<string, bool, tuple<variant<int, string>, variant<int, string>>> tup = { "hi", {}, { "lol", 1} };
    

    auto lol1 = stct.pr.first.s; //< natural access order, digging deeper into the struct
    
    auto lol2 = get<string>(get<0>(get<2>(tup))); //< reversed access, also, welcome to hell
    
    auto lol3 = tup.[2].[0].[string]; //< natural access order again
   

I don't think we need to access this kind of structs by index and type in generic code. IN generic code I wouln't mind to reverse the order if needed. Do you have an example?

Granted, a universal call syntax would render this example much less attractive.



Could you elaborate? get<I>(t) was chosen because t.get<I>() doesn't works always, we need template.

struct P {
    std::pair<int, int> data;
    template <size_t I>
    int& get() { return std::get<I>(data); }
};

template <class T>
auto f(T & v) {
    //v.get<0>(); // COMPILE FAILS
    v.template get<0>();
}

http://melpon.org/wandbox/permlink/QLslsrDEHgV2zdlX

You can already have a product type
chain adaptor

    as_pt(lot2)(nth<2>, nth<3>, type<string>)

It is not so friendly but it should works.


http://melpon.org/wandbox/permlink/Oda6XwY2lIHD2XMU

Vicente

P.S. Note that I'm not against having a way to index product types, but it is not so simple to find the appropriated syntax without breaking changes and without ambiguity.


What about


    auto lol3 = tup : 2 : 0 : string;

or

    auto lol3 = tup : <2,0,string>;


':' after a product type will accept an index or a type or a sequence of index or types

I don't know if this could be a breaking change or needs too much look ahead.



mihailn...@gmail.com

unread,
Oct 23, 2016, 3:05:49 PM10/23/16
to ISO C++ Standard - Future Proposals, mihailn...@gmail.com


On Sunday, October 23, 2016 at 8:32:00 PM UTC+3, Vicente J. Botet Escriba wrote:
Le 23/10/2016 à 13:59, mihailn...@gmail.com a écrit :
...
I don't think we need to access this kind of structs by index and type in generic code. IN generic code I wouln't mind to reverse the order if needed. Do you have an example?
Granted, a universal call syntax would render this example much less attractive.


Could you elaborate? get<I>(t) was chosen because t.get<I>() doesn't works always, we need template.
      ...

Yeah, in generic code, the standard, non-universal syntax, will be used. The point was for regular, simple uses (and users...).

As for, do we need access of structs by index - this will allow code written against a tuple to accept a struct also.
An algorithm can be written against a generic "type with this number of fields of this and this type" without care what the containing type is.
There is already such symmetry b/w pair, tuple and array and I think it is a good thing.

The idea is, this access to be for types (not only pt-s) what iterators are to containers - the real type of the container does not matter for the access.

Having said that, to have this as default for every possible type is probably not a good idea, still, easy adaptors should be possible.


In any case. This is not the core of the proposal !


The core is - to have native access for tuples and, for the time being, until a build-in type, for variant as well.

The reason is, tuple access will not change - be it build-in or library, it will always be access pretty much the same way - either by integer or type index.
Considering it is a core "vocabulary" type now, the awkward way it is access is quite glaring. Especially for a new comer.

After all, the tuple is not just for template metaprogrammers - it is as basic a s struct, arguably even more basic!
Considering tuple is here to stay, its access should be promoted to a language feature, so new comers can get a feel for it more easily.
(Again, no matter the impl. of tuple, the access will be the same)

That is the reason for the proposed syntax as well - the mix of two basic expressions which are learned in the first week (probably).

Dot means - dig into a struct to get a contained object
A number surrounded with square brackets means "index", note, not just in C/C++ but in other, non-programming places like Wikipedia page references and others.

Combined, dot and number-in-beckets, just mean dig into "a struct" and pick at this index.
(The user should not think much about templates at this point - even if told what template is, he will be told in the context of tuple<int, string> or vector<int>,
not in the context of passing is as an argument to a function, which is weird even in normal, day to day c++!)

Lastly, in the context of the fancy structured bindings, the lack of a native way to pick just one element is simply sad.  


Reply all
Reply to author
Forward
0 new messages