0

So I tried yesterday to start using std::initializer_list but that wasn't a huge success. There is one of my last try:

#include <unordered_map>
#include <string>

     struct XmlState {

        using U_StateFunc = std::function<void()>;
        using U_MapStateFunc = std::unordered_map<std::string, U_StateFunc>;

        U_StateFunc     beforeProcess;
        U_StateFunc     afterProcess;
        U_MapStateFunc  funcMap;

        XmlState
          (U_StateFunc&& bProcess,
           U_StateFunc&& aProcess,
           std::initializer_list<typename U_MapStateFunc::value_type> mapParams)
          : beforeProcess(std::move(bProcess)),
            afterProcess(std::move(aProcess)),
            funcMap(mapParams)
        {}
      };

      template < size_t NB_STATES >
      class XmlParser {

        using U_StateArray = std::array<XmlState, NB_STATES>;
        U_StateArray  m_states;

        public:
          XmlParser
            (std::initializer_list<typename U_StateArray::value_type> states)
            : m_states{states}
          {}

      };

      XmlParser<1>  test {
      {
        {
            XmlState::U_StateFunc(), XmlState::U_StateFunc(),
            {
              { "Tag1", []() {} },
              { "Tag2", []() {} },
              { "Tag3", []() {} }
            }
        }
      }};

int main() {}

Wandbox

I'm wondering why I struggle so much to use this. {} this is a std::initializer_list empty, and {{}} this is one with one element right? But you need to put them inside the constructor like Foo({{}}) ? Or using another list Foo{{{}}}. I mean, this looks simple, but I just can't make it happen.

Btw I'd like to know if it's better to use initializer_list or template parameter pack? Both with move semantic, because there is no temporary object with parameter pack after all?

Mathieu Van Nevel
  • 1,428
  • 1
  • 10
  • 26
  • `std::array` can use [aggregate initialization](http://en.cppreference.com/w/cpp/language/aggregate_initialization) but it does not have a constructor that can deal with `std::initializer_list`. – super Feb 25 '18 at 13:06
  • @super I tried with parameter pack without success too. Do you have any clues? – Mathieu Van Nevel Feb 25 '18 at 15:24

1 Answers1

1

Not sure if this is what you are looking for, but if you change XmlParser to take a U_StateArray in the constructor, you can make the syntax close to your original.

//Changed constructor in XmlParser
XmlParser (U_StateArray states) : m_states{states} {}

//Used like this
XmlParser<2>  test {{

        XmlState(XmlState::U_StateFunc(), XmlState::U_StateFunc(),
        {
          { "Tag1", []() {} },
          { "Tag2", []() {} },
          { "Tag3", []() {} }
        }),

        XmlState(XmlState::U_StateFunc(), XmlState::U_StateFunc(),
        {
          { "Tag4", []() {} },
          { "Tag5", []() {} }
        })

}};

Another option is to change the std::array to a std::vector. Then your code works since std::vector has a constructor for std::initializer_list.

A third option is to make a helper, that takes an std::initializer_list and returns an appropriate std::array. Like suggested here.

super
  • 12,335
  • 2
  • 19
  • 29