This is a pattern I came across while fiddling with tuples and type tuples for a ECS project I’m working on. This is inspired on boost::hana, which is a lovely template metaprogramming library, and provides tuple access with operator[] .

std::tuple and std::get

std::tuple is awesome. C++11 came with a lot of goodies and std::tuple allows for a lot of generic programming code to be written. However, accessing members of the tuple can only be done through std::get , which is not a member function, and there is a very good reason for it not to be a member function. Suppose the following illustrative case:

The reason the commented code does not work is that when get is a dependent name, using an explicit template instantiation requires declaring it as a template, which is very less appealing for the user. So how to fix this? The first thing to notice is that the index(or type) of the access is always known at compile time, so instead of explicitly instantiating the parameter, one may pass a type corresponding to the index as an argument. Modern template metaprogramming libraries use this technique to improve syntax. So how to pass the index as a type? std::integral_constant to the rescue. Observe the following implementation:

Here, get is invoked with a regular member syntax, so no need for the template keyword, despite it actually being a template method. This technique allows replacing the get member with operator[] allowing for a more familiar uniform access pattern. This still does not look so good, though. idx_c<> is too much typing for something used so frequently, and template methods on template classes are things that might slow down your compilation, and fill your terminal with lines and lines of obscure error messages when something goes wrong. What else can we work on? When using variadic templates, the classic approach is to use recursion with inheritances, which can further extend your compiler error messages, but more advanced implementations may use a “parallel” method. In fact, this approach allows us to reduce one level of templating for the access methods. Consider the following implementation:

kv_map is a tagged holder, which exposes a single non-template operator[] , that takes an object of class K which works as the key, and returns the held value of type V . Building on the key-value mapping, we make a simple map , and our tuple may be thought as a mapping of a std::integral_constant to a given type. tuple_base is an indirection level to specialize from a type list to a sequence of kv_pairs , and tuple provides our actual interface. Although there is some level of indirection involved, when the type of the tuple is known, code completion engines will be able to list all available operator[] for an instance. This comes with a trade off: when using a templated method, the instantiations are lazy, so if you never call the operator for some type, it wont be instantiated; with this method, all methods are compiled for each kv_pair instantiated. This could lead to larger binaries, but most of the times, LTO should be able to strip the binaries from all the unused methods. As for the excess typing on idx_c ? boost::hana makes use of the numeric literal operator template, to turn a integer to a integral_constant like this, 42_c . One way to implement the literal operator _c , is the following:

this gives tuple access with t[0_c] , which is fairly reasonable. interestingly, if t happens to be not a tuple, but any type which accepts a std::size_t as parameter, it would work through implicit conversion of the integral constant.

I found this pattern to be useful, and hopefully it might be insightful for you, reader.

[],