Yup. I reached the same idea a while ago. I didn't use a hash for the fields though. If you think about it, you don't need a hash function at all. A hash function actually slows down compile times! At compile time, you just resolve all the names to offsets in the tuple (simpler, and the added benefit of no hash collisions). I created a "Symbol" type for string constexpr's and used a user defined literal for them.
It seems to me like Boost.Hana is the natural way to do it.
WTF? Just use a struct. And interop with existing tuples; maybe conversion constructor and operator cast. 10 lines everybody can understand, not some crazy shit.
Indeed, a structure is a named tuple. I think there's a subset of C++ users who pride themselves on creating massively complex solutions, as if they're trying to use as much of the features of the language as they can, instead of going for the simple, straightforward solution. AFAIK std::tuple does compile into the same code as if you declared a struct yourself, but I'd like to see what this convoluted solution compiles to... if I'm reading it correctly, this turns into an O(n) structure member access!?
What if You by mistake switch ‘GPA’ and ‘grade’ inside your function? Nothing will happen to inform You that something went wrong.
I don't know if there's a specific name for it, but "what if you did X" arguments like this fail to convince me.
That variadic expansion happens at compile time, so it's still O(1) access. In my experience, the effects of something like this won't be immediately visible. You might start to notice compile times creeping up as the project grows. YMMV.
This does seem a bit crazy, but it's worth remembering that the named tuple is copied from Python. Although I suppose the excuse there is a lack of structs.
But you can generate them with macros. The Boost preprocessor library can help a lot.
At work we use kind of a hybrid approach. We have generator macros that spit out named tuple classes that use a bunch of magic and template meta-programming.
It should go without saying that the macro implementation is ugly and only a few people understand it very well, but we don't have to change them much any more, and the resulting named tuples are easy to use and generally work exactly as expected.
Yes, lots of people do named tuples with preprocessor logic of one kind or another (protoc and a variety of serialization libraries basically give this to you). It's much cleaner if you can use the type system to do the job for you.
It's been a while since I even considered doing something like this, but you could probably generate them by recursively inheriting from a chain of generated base classes.
That said, most everyone who's looked at the problem has ended up going with macros instead. :-)
Why would you want to create a named tuple by invoking convoluted code (and arguable with the end result being also not trivial to use) instead of just declaring a structure?
This article is interesting to explore the technical capabilities of modern C++, but not to use the result...
Because I don't know what I want until I want it. I do a similar Tuple a couple of times I know I am going to need a container class/struct to avoid rewriting the same Tuple over and over again and it would also make things clearer as I know got a class/struct for that particular use case.
Now until I know I need one, it's unnecessary to clutter the namespace with yet another container class/struct.
Named Tuple has a few benefits, that's all. Until they don't.
Given the implementation, there is nothing lightweight and low-overhead to use at build time, and at runtime how exactly is this lighter than a struct? As for self-documenting, I don't even know what it would mean here.
Remains "iterable". Given how modern compiler works, I'm still convinced you should convert plain tuples back and to a struct for source code simplicity and build time speed -- because it won't even do extra copies in most cases (and even if it does, who cares?)
One great use of named tuples would be named function arguments. I've grown tired of seeing functions that take a bunch of doubles and always checking which argument is which.
Yeah, tuples make sense sometimes, that's why they are introduced. I think iterating through a tuple only makes sense if you store in some kind "similar" elements in there (not necessarily same type but same trait class). It could indeed be great for generic programming where your tuple have variadic length (depending on template parameters).
Just don't use it to replace structs, it doesn't make sense.
You can do metaprogramming things like iterate over the fields of a tuple or unpack it into the arguments of a function, but you can't with a struct (without manually defining an array of fields).
You use this if you want to _appear_ smart, and you use structs if you actually _are_ smart. Smart programmers do not introduce gratuitous complexity into their code.
Looks very nice. The nice thing about tuples is they can be manipulated generically to do some really cool stuff like destructuring and pattern matching, serialization, remote marshalling, etc. Making them easier to use is a win for all.
I always shy away from clever solutions that involve semantics that's not obvious to the reader. If something using this code lends on your lap you are going to spend hours tracking its source, figuring out what the author was trying to say, etc.
I know, I've been there. Making my coworkers' lives harder than it needed to be with clever template magic didn't help anyone. I ripped that code out soon after.
But if the code like this is well contained, and is there to solve a very specific problem that maintainers will be able to handle, then go for it.
Just use two parallel containers: one for names, and one for values. It is dead simple to check that they have the same size and iterate over both simultaneously where needed. And the best part is, for code that does not actually require both pieces of information, you can pass one of the lists and pretend that the other does not exist. Code that only knows how to visit values only has to deal with values and not weird hybrid name/value elements.
Seriously, always try the simpler thing first. Do not go deeper into templates and special syntax before seeing if any other construct will do the job.
Is this only appropriate for the case where we want to iterate over all the elements? Don't we lose the O(1) access using a name? I'm assuming you're making 2 arrays.
Yes. My point is to consider what is actually required before making complex structures. It is often perfectly acceptable to combine two existing types and handle what few interactions they actually have.
> 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...
I'd still use a custom struct with named fields. I don't see the above being anywhere close to justifying the additional complexity.
It seems to me like Boost.Hana is the natural way to do it.