2

Sorry for the format, I never really posted to a forum like this, so I have to learn the how to a bit.

My problem is: I'm writing a template class, and I'd like to access my containers via multiple kind of [] operators. I read a bit in this subject, so I've been able to make one overloading, but I need some more:

So in my header file, relevant things about my container:

template <class T>
class version_controlled_vector
{
    int rev;                                         
    bool vector_state_changed;
    std::vector< std::string > revision;     
    std::vector< std::vector<T> > v;                 


    //first one works ok, im satisfied with it:
    std::vector<T>& operator[] (const int idx)
    {
        return v[idx];
    }

    //im not sure how to define the further one(s?):
    T& operator[](const int idx2) const
    {
        return v[idx2];
    }
    //...and ofc some other code
};

//to have these usages at my main.cpp:

version_controlled_vector<int> mi;
version_controlled_vector<std::string> ms;

//this works, and i d like to keep it,
5 == mi[ 0 ][ 0 ];

//and i d like to have these two usages too:
//getting the first character of the stored string:

'H' == ms[ 0 ][ 0 ];    // with the first overload from the header ms[0][0][0]    
works  to get the first character of the string for eg "Hello" 
but, i have to use  the ms[0][0] format to achieve this

//and this:
4 == mi[ 0 ]; // i d like this as if it d behave like 4 == mi[0][0];

I don't really get how can I use the single[] when I made an overload to use the [][]

The only solution I have read about is maybe const-overloading, but I'm not sure at all, I'm quite a weakie.

Thanks for ideas!

PiotrWolkowski
  • 8,408
  • 6
  • 48
  • 68
  • First off, welcome to StackOverflow (Not a forum, but a Q&A site). Now, going to the basics: What do you mean by "version-controlled vector? Does it mean your class must start a new revision whenever the content of the container changes? Because then you are definitely exposing the internal vector too much. (Which btw. already has a subscript operator) Related reading: [Operator overloading](http://stackoverflow.com/questions/4421706/operator-overloading) – Deduplicator Jun 29 '14 at 22:07
  • I don't understand what you are after. You want `mi[0]` to be an `int`, but `mi[0][0]` to also be an `int`? – Vaughn Cato Jun 29 '14 at 22:12
  • Your intention for overloading `operator[]` is not clear at all. And what part does `revision` play in any of this? If none, why is it even in your sample? – WhozCraig Jun 29 '14 at 22:17
  • Vaughn Cato: yes, i d like to access mi[0][0] with the syntax mi[0], so to an int. WhozCraig: yes revision is not really relevant part here. This program is practising, and its my first post, so i made this mistake, at least leared from it :) Basically its a container, where i can store data of different versions in separate vectors. revision vector can contain a comment for each version. main is made by someone else, and i have to implement the header. to say the truth goal of single [] is a bit unclear for me, especially if we have [][] to access everyting. anyway thanks for answers – captain_stack Jun 29 '14 at 22:37

2 Answers2

1

I think you are muddying the interface of the class. The expectations from the class are:

  1. Get the i-th value from the j-th version.
  2. Get the i-th value from the latest version.
  3. Get the j-th version.

You have the option of using the overloaded operator[] function to get those values but, it will be better to have functions that reflect the interface.

// Get the versionIndex-th version.
std::vector<T>& getVersion(int versionIndex);

// Get the itemIndex-th value from the versionIndex-th version.
T& getItem(int versionIndex, int itemIndex);

// Get the itemIndex-th value from the latest version.
T& getItem(int itemIndex);

Then, the implementation would be simpler and less confusing.

std::vector<T>& getVersion(int versionIndex)
{
    // Make sure to add out of bound checks
   return v[versinIndex];
}

T& getItem(int versionIndex, int itemIndex)
{
    // Make sure to add out of bound checks
   return v[versinIndex][itemIndex];
}

T& getItem(int itemIndex);
{
    // Make sure to add out of bound checks
   return v.back()[itemIndex];
}

Given these, the only operator[] that makes sense, at least to me, is one that returns the i-th value from the latest version.

T& operator[](int itemIndex);
{
    // Make sure to add out of bound checks
   return v.back()[itemIndex];
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Why not use a magic proxy? It can just work for this case, unless `T` has a subscript operator... – Deduplicator Jun 29 '14 at 22:31
  • @Deduplicator, please elaborate what you mean by "magic proxy". – R Sahu Jun 29 '14 at 22:33
  • Letting the subscript return a class which can be implicitly converted to `T`, as well as providing a subscript operator for the second level. – Deduplicator Jun 29 '14 at 22:44
  • @Deduplicator, I looked for a way to do that, but I didn't find a simple way. – R Sahu Jun 29 '14 at 22:55
  • @captain_stack, The outcome of `ms[0][0]` depends on the what `ms[0]` evaluates to. If you are happy with `ms[0]` returning the 0-th item of the latest `std::vector`, then, the function I have in the answer is good. – R Sahu Jun 29 '14 at 23:22
0

It's a bit tricky one, you need to realise that when you write

version_controlled_vector<int> mi;
5 == mi[0][0];

during the second fetch you're no longer accessing your version_controlled_vector class but the inner property of it and it's type is std::vector<T> which has its own subscript operator that you call in the second [0].

To control the subscript operator of the second fetch you need to create another class that derives from std::vector<T> and has overloaded subscript operator. Then you should use this class instead of the std::vector in the implementation of version_controlled_vector.

vnd
  • 356
  • 1
  • 6