HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

C++ tuple implementation with get as a member

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withtuplegetmemberimplementation

Problem

If you're familiar with std::tuple, you're aware that accessing its elements is slightly unusual. Instead of using a member function, we're provided with the function std::get instead. I was curious as to why this is, so I conducted a brief search. The few websites that I saw all gave the same reason: the code used to called the method is ugly.

We would expect:

my_tuple.get()


but apparently we would have to write:

my_tuple.template get()


(a source, see footnote 5).

This seemed like a bad case of "I heard that she heard that he heard...", because I was unable to find an implementation of a tuple that exposed this ugliness by including get as a member. I heard that Boost's tuple had get as a member, but after inspecting the source I discovered that it also only accepted 10 elements max. It was time for me to implement it myself!

template 
class Tuple
{

};

template 
struct TypeHolder;

template 
struct TypeHolder>
{
    typedef typename TypeHolder>::type type;
};

template 
struct TypeHolder>
{
    typedef R type;
};

template 
class Tuple : public Tuple
{
public:
    Tuple(T obj, Ts... objs)
        : Tuple{ std::forward(objs)... }
        , obj{obj}
    {

    }

    template 
    typename std::enable_if>::type&
    >::type get()
    {
        return obj;
    }

    template 
    typename std::enable_if>::type&
    >::type get()
    {
        return static_cast*>(this)->get();
    }

protected:
    T obj;
};


This functions as expected, and after some brief testing I found that there were no issues with storing pointers or references. But there was no need to write "template" for every call to get! (My compiler is GCC, by the way.)

Is there a reason why std::tuple was not implemented in this way? I would like to know about any glaring flaws with this code before I move forward with it.

Solution

Your source is not very specific as to why/when my_tuple.template get() is required.

If you have code like this:

Tuple x(1,2,3);
int i = x.get();


That is fine, because all template arguments to Tuple are known at the time of parsing and Tuple is instantiated immediately, before the call to get is parsed. At that point the compiler already knows that in that specific instantiation of Tuple get is member function template rather than a non-template member and everything is ok.

This however

template
auto foo(T t) {
    Tuple x(t,2,3);
    return x.get();
}


generates a compiler error, because when foo is parsed, the actual type of T is not known and instantiation of Tuple needs to be delayed until instantiation of foo. This means that when x.get is parsed, the compiler does not yet know what kind of language construct get is in the instatiation of Tuple and in fact it may very well vary for different T. Therefore it is assumed that get is a non-template member, which doesn't make sense considering the following template argument list.

Your code sadly does not solve this problem and I don't think it is solvable.

Additionally I noticed that your Tuple is an empty class if an empty type list is given. That is a bit inconsistent. I think at least get should be provided as empty function. Calling it should not be allowed, but referring to the member function should be fine.

Code Snippets

Tuple<int, double, float> x(1,2,3);
int i = x.get<0>();
template<typename T>
auto foo(T t) {
    Tuple<T,int,double> x(t,2,3);
    return x.get<0>();
}

Context

StackExchange Code Review Q#142462, answer score: 4

Revisions (0)

No revisions yet.