Overloading subscript operator

Sep 1, 2017 at 9:25pm
Hi, I would like to overload the subscript operator so that I can use tuples like an array
e.g.
mytuple[0];

Here is what I've coded, but I am new to using templates so I don't know what is happening, could someone tell me what I'm doing wrong & what should be done?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <tuple>

template <typename T>
T tuple::operator[](const int index) {
return get<index>(tuple);
}
...

int main() 
{
    int a=14;
    tuple<int,string,char> myTuple;
    myTuple[0]=1;
    a=myTuple[0];
    ...
return 0;
Sep 1, 2017 at 11:53pm
You can't. See SO for why: https://stackoverflow.com/questions/32606464/why-can-we-not-access-elements-of-a-tuple-by-index

(You have also chosen one of the most complex classes in the Standard Library to dink with.)

Hope this helps.
Sep 2, 2017 at 4:02am
> Hi, I would like to overload the subscript operator so that I can use tuples like an array
> e.g. mytuple[0];

This is possible only if the index is an integral constant expression wrapped in a template.

A la place holders for std::bind():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <tuple>
#include <string>

namespace my
{
     template < std::size_t N > struct index {} ;

     template< typename... T > struct tuple : std::tuple<T...>
     {
         using std::tuple<T...>::tuple ;

         template < std::size_t N > constexpr decltype(auto) operator[] ( index<N> )
         { return std::get<N>(*this) ; }

         template < std::size_t N > constexpr decltype(auto) operator[] ( index<N> ) const
         { return std::get<N>(*this) ; }
     };

     constexpr index<0> _0 {} ; constexpr index<1> _1 {} ;
     constexpr index<2> _2 {} ; constexpr index<3> _3 {} ; // etc

     // TO DO: make_my_tuple etc.
}

int main()
{
    using namespace my ;

    tuple< int, std::string, const char*, char > my_tup {} ;

    my_tup[_0] = 1;
    my_tup[_1] = " hello" ;
    my_tup[_2] = " world" ;
    my_tup[_3] = '!' ;

    std::cout << my_tup[_0] << my_tup[_1] << my_tup[_2] << my_tup[_3] << '\n' ;
}

http://coliru.stacked-crooked.com/a/82b4d508ebc97ebf
Sep 2, 2017 at 6:37am
Another very similar approach.
Wrote this out earlier today, but never posted it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# include <tuple>
# include <type_traits>

namespace my {
    template <typename... Ts> class tuple: public std::tuple<Ts...> {
        using base = std::tuple<Ts...>;
    public:
        using base::base;
        
        template <std::size_t I>
        constexpr decltype(auto) 
        operator[](std::integral_constant<std::size_t, I>) 
        { return std::get<I>(*this); }
    };
    
    template <typename... Args>
    tuple(Args...) -> tuple<Args...>;
    
    template <int I> 
    constexpr auto size_t_c = std::integral_constant<std::size_t, I>{};
}

# include <iostream>

int main() {
    my::tuple t{1, "hello!", 25.3, 4};
    std::cout << t[my::size_t_c<1>] << '\n';
}


http://coliru.stacked-crooked.com/a/bc96651e1a996495

I was also going to add that it is mostly prohibited to add behavior to the standard library. This is at least because the implementation may rely on the interface to select the correct behavior.
Last edited on Sep 2, 2017 at 6:51am
Topic archived. No new replies allowed.