0

I have implemented a structure for containing configuration data using the stl::map back end. I have implemented the [] operator as:

string& config:operator[] ( const string theKey )
{
    ParamMapIter iter;

    iter = _configMap.find ( theKey );

    if ( iter == _configMap.end() )
    {
        _configMap[theKey] = "";     // Create a new blank key/value when missing key
    }

    return _configMap[theKey];
}

so I can do things like

Conf["key"] = "value";

Now I'd like to make this semi-two dimensional to match old style Windows config files with separate sections. e.g. so I can write

Conf["section"] ["key"] = "value";

Any suggestions on how to implement this efficiently?

I guess the real question is how to implement the double subscript. The underlying implementation would take care of the actual detail - though suggestions on that also appreciated.

  • 2
    `( const string& theKey )` would be a good start. – Bathsheba Sep 11 '14 at 11:31
  • Then your first `operator []` will have to return a reference to something that implements `operator []`. Also, `std::map`'s `operator []` will automatically insert a value-initialized element if the key isn't found. No need to do manual initialization. – T.C. Sep 11 '14 at 11:33
  • 2
    Your whole function could be replaced by `return _configMap[theKey]`. That already creates an empty entry if the key doesn't exist. – M.M Sep 11 '14 at 11:33
  • possible duplicate of [Operator\[\]\[\] overload](http://stackoverflow.com/questions/6969881/operator-overload) – ikh Sep 11 '14 at 11:35
  • 3
    perhaps you want `std::map< std::string, std::map >` ? Then you just use it like `Conf["key1"]["key2"] = "bar";` – M.M Sep 11 '14 at 11:35
  • Does it have to match both `Conf["key1"]["key2"] = "bar";` and `Conf["key1"] = "foo";`? – Surt Sep 11 '14 at 12:03

2 Answers2

1

std::map gives you the "create if not existing" functionality in operator[]

See std::map::operator[]

If k does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the container size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).

Or C++ standard [23.4.4.3 map element access]

T& operator[](const key_type& x);

1 Effects: If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map.

2 Requires: key_type shall be CopyInsertable and mapped_type shall be DefaultInsertable into *this.

3 Returns: A reference to the mapped_type corresponding to x in *this.

4 Complexity: logarithmic.

T& operator[](key_type&& x);

5 Effects: If there is no key equivalent to x in the map, inserts value_type(std::move(x), T()) into the map.

6 Requires: mapped_type shall be DefaultInsertable into *this.

7 Returns: A reference to the mapped_type corresponding to x in *this.

8 Complexity: logarithmic.

So if you was adding only the operator[] functionality you can simply do

typedef std::map<std::string, std::map<std::string, std::string>> config;
// or in C++11 style
// using config = std::map<std::string, std::map<std::string, std::string>>;

config Conf; 
std::map<std::string, std::string>& section = Conf["Section"];
// or again in C++11
// auto &section = Conf["Section"];
section["key"] = "value";
Dawid
  • 623
  • 3
  • 9
1

Does it have to match both Conf["key1"]["key2"] = "bar"; and Conf["key1"] = "foo";?

Then you will have to define a Section that is just like your current Config, except as below.

Change the Config [] to return a &Section.

Make an overload operator= taking a Key (ie. a std::string) this makes it possible to implement Conf["key1"] = "foo"; in the operator=

_sectionMap[""] = value;

and adding operator std::string to return _sectionMap[""]

This makes the Section key "" the same as the value Config[key1].

Surt
  • 15,501
  • 3
  • 23
  • 39