Named tuple for C++

named tuple for cpp

When I use std::pair or std::tuple I always feel sad about using std::get<> to get results. Because this is not so readable, not so maintainable and a bit ugly. Even when you use first/second it’s easy to forget what was first argument of std::pair and so on. When you use tuple to pass more than 3 arguments situation becomes even worse. New standard has nothing in box to solve this, but we can fix this writing our own solution using C++14.

At MeetingCPP 2015 conference I attended nice presentation by  and found great solution there – named tuple. After some playtime I made my own implementation draft which you can find in this post.

Ok, once again – what’s else wrong with std::tuple?

Look at standard example from cppreference.com:

What if You by mistake switch ‘GPA’ and ‘grade’ inside your function? Nothing will happen to inform You that something went wrong. Information will still be passed to std::make_tuple, and auto-converted to std::cout. Except the output will be totally wrong… Is there some way to avoid this situation? A lot of you now are thinking about making custom struct with named fields, than and passing typed result as this struct. This is good solution and there are a lot of cases when this will be actually better, but … this is not so simple.

But what if you know that this temporary structure is rather limited in size and will be used just ‘here’ to pass results (and so creating of additional class to pass result will be overhead) – there is nice solution from python – named tuple.

C++14 is powerful enough to make our own named tuple. The only problem is that final syntax could be different depending on our own choice. I have chosen the following:

Creation: Instead of make_tuple() here we have make_named_tuple() and param() is creating named parameter which is set in place.

Access: To access data I use square bracers and same named parameter inside.

There are a lot of other ways to declare this – you are free to use your own syntax. It will be better then std::get<> anyway.

IMPLEMENTATION of tagged tuple

The main trick here is compile time string hash. It does not matter which specific implementation You choose for it – I just grabbed the one from Manu’s gist:

Next is simple class for named param:

Nothing special as You could see – i just store optional value inside inner tuple. So parameter could be empty and be used as static search key or it can contain some value and be passed to tuple construction function.

Now main tuple struct. To make it work with Visual Studio’s compiler I came up with this:

And finally make_named_tuple() and param():

Yes, that’s all!

CONCLUSION

So we now have rather compact way to create named tuples in C++. This has to improve readability and simplicity of any code dealing with std::tuples and std::pairs.

And what is even more important – this scheme is more error proof. When you change places of arguments in tuple – nothing happens – everything will still work. If you make mistake in parameter name – you will get compile error right away. If during project lifetime You decide to refactor your tuple structure you will get all places where you need to change access functions, because until you do this compiler will not produce any executable. Sweet.

Source code: gist

  • Pingback: Named tuple for C++ | Daily Hackers News()

  • http://kalx.net Keith A. Lewis

    How is this better than:
    enum { GPA, grade, name };
    auto student = make_tuple(3.8, ‘A’, “Lisa Simpson”);
    cout << "GPA: " << get(student)
    << "grade: << get(student)
    << "name" << get(student) << endl;
    ?

    • Victor Laskin

      You have to put enumeration into global scope. Can’t really use something like this:

      auto f = [](){
      enum { GPA, grade, name };
      auto student = make_tuple(3.8, ‘A’, “Lisa Simpson”);
      return student;
      };

      And if you go this way – it’s better use custom struct instead of enum.

      Once again – proposed solution is for cases where you used std::pair / std::tuple in your code. I’m not suggesting to replace structs/classes as return types.

  • Milan Jarić

    And why is this preferred comparing to defining struct type if nameing is important? It is less readable this way and I see in comments enum which I would rather use than making so much annotations and reusable for other tuples with same or similar structure

    • Victor Laskin

      This is solution when you don’t want to add some new structure/enum into global space. The best alternative in that case would be using anonymous structs from C++11. And they are good enough for a lot of such cases.

      Named tuple has advantages of std::tuple. As they have comparison operation out of the box you can pass result into std::sort for example. And more – such structure could be extended to support additional functionality in future (such as serialisation to JSON, easy introspection, concatenation of such tuples, iterations over list of members, etc)

  • Manu343726

    Hi Victor, I forgot to tell you that Jonathan Müller noticed a couple of months ago the factor being used for the constexpr hash is not prime. I have an open issue in our ctti library regarding this https://github.com/Manu343726/ctti/issues/11

    • Victor Laskin

      Manu, Thanks a lot for info. I guess the fix is simple – just enter right prime number. Please write me when the fix will be merged inside your ctti lib.