Overload vector subscript operator to take a char

2019-08-14 06:23发布

问题:

I am trying to overload the subscript operator -i know it as the element access operator- to take a char * or a std::string.

I have a struct

struct foo
{
    int Age;
    const char *Name;
};

and a std::vector that will be holding multiple instances of this struct.

std::vector<foo>bar;

my goal is to be able to access each foo in bar by calling them by their name.

std::cout<<"Simon's age is: "<<bar["simon"];

I've just been searching google for a long while trying to find an example or something to go off, with no luck.

i thought that this would work

foo operator[](char *Name)
{
    for(int i=0;i<bar.size();i++)
    {
        if(bar[i].Name == Name){return bar[i];}
    }
}

however apparently i'm doing something wrong

I do know this could be done with an std::map but i'd rather use an std::vector, thanks.

I would greatly appreciate your help however you choose to offer it. Thank you .

回答1:

To do what you want requires inheriting from std::vector. Otherwise you can't overload its methods.

Something like the following (untested).

struct fooVector : public std::vector<foo> {
    typedef std::vector<foo> super;
    using super::size;
...
    foo& operator[](char const* Name) {
       super& self=*this;
       for(int i=0;i<size();i++)
       {
           if( ! strcmp( self[i].Name, Name) ){return self[i];}
       }
       // Need to do something reasonable if not found
    }
};


回答2:

bar[i].Name == Name

was probably meant to be

strcmp(bar[i].Name, Name) == 0

However, you'll be better off using std::strings than managing plain char pointers.

And instead of inheriting form a vector, create a class with a vector as a member and have your operator[] on that class.



回答3:

First of all there are some problems with your test:

1) you're using const char* for string type, comparing with == would likely fail as you're comparing two pointers and not their content. you need to use strcmp or better use std::string (c++ way)

2) what if your index operator would not find the value you're looking for?

I don't think this is a proper way of doing this but in case you really want to use vector you can inherit your own class and define new operator which uses const char* as a index argument:

#include <vector>
#include <iostream>
#include <string.h>

struct foo {
    int age;
    const char *name;
};

class MyVector : public std::vector<foo> {
public:
    const foo* operator[](const char* name) const {
        for (auto it=cbegin(); it != cend(); ++it) {
            if (strcmp(it->name, name) == 0) {
                return &(*it);
            }
        }
        return nullptr;
    }
};

int main(int argc, char *argv[]) {
    foo foo1 = { 10, "abc" };
    foo foo2 = { 20, "test" };

    MyVector v;
    v.push_back(foo1);
    v.push_back(foo2);

    std::cout << "test: " << v["test"]->age << std::endl;
}

Although it's not generally advised to inherit from stl containers (they don't have virtual destructors), if you don't add any data attributes to inherited class you should be fine.

But I would suggest you to consider using std::map as a container and std::string as index / name attribute type. Searching vector has linear complexity but std::map has logaritmic complexity. Or you can consider using hash tables.