Search code examples
c++stdstdmapinitializer-list

Constructor with initializer list for std::map


Following the advice of not extending std containers from this question , I am creating my own type and using std::map as a class attribute.

I am re-creating the public interface functions I want from std::map, forwarding them to the class attribute. How do I specify a constructor that takes an initializer list as a parameter? I am using a map<int, vector>.

First attempt using an initializer_list<pair<int, vector<int>> :

class IdParentingMap
{
public:
   using DataMap = std::map<int, std::vector<int>>;
   using DataMapIt = DataMap::iterator;
   using DataMapConstIt = DataMap::const_iterator;

   IdParentingMap();
   IdParentingMap(std::initializer_list<std::pair<int, std::vector<int>>> initList);

   DataMapConstIt findParentIt(const int id) const;

   /** Forwards from std::map  **/

   std::size_t size() const;
   DataMapIt end();
   DataMapConstIt end() const;

private:
   DataMap data;
};

IdParentingMap::IdParentingMap(initializer_list<pair<int, vector<int>>> initList)
  : data(initList)
{
}

gives me (from the compiler) :

In constructor 'IdParentingMap::IdParentingMap(std::initializer_list<std::pair<int, std::vector<int> > >)':
<source>:27:5: error: no matching function for call to 'std::map<int, std::vector<int> >::map(std::initializer_list<std::pair<int, std::vector<int> > >&)'
   27 |   : data(initList)
      |     ^~~~~~~~~~~~~~

In file included from /opt/co Second attempt using an initializer_list<pair<int, initializer_list<int>> :

class IdParentingMap
{
public:
   using DataMap = std::map<int, std::vector<int>>;
   using DataMapIt = DataMap::iterator;
   using DataMapConstIt = DataMap::const_iterator;

   IdParentingMap();
   IdParentingMap(std::initializer_list<std::pair<int, std::initializer_list<int>>> initList);

   DataMapConstIt findParentIt(const int id) const;

   /** Forwards from std::map  **/

   std::size_t size() const;
   DataMapIt end();
   DataMapConstIt end() const;

private:
   DataMap data;
};

IdParentingMap::IdParentingMap(initializer_list<pair<int, initializer_list<int>>> initList)
  : data(initList)
{
}

gives me (from the compiler) :

In constructor 'IdParentingMap::IdParentingMap(std::initializer_list<std::pair<int, std::initializer_list<int> > >)':
error: no matching function for call to 'std::map<int, std::vector<int> >::map(std::initializer_list<std::pair<int, std::initializer_list<int> > >&)'
   27 |   : data(initList)
      |     ^~~~~~~~~~~~~~

Solution

  • When mimicing the interface of another class, an easy way to "get it right" is to make the same type definitions as in the original class and then use these definitions in the member functions. Example:

    class IdParentingMap {
    public:
        using DataMap = std::map<int, std::vector<int>>;
        using value_type = DataMap::value_type; // use the the original typedef(1)
    
        IdParentingMap(std::initializer_list<value_type> initList);
    //                                       ^^^^^^^^^^
    };
    
    1. Note that the original type definition is std::pair<const Key, T>.