Search code examples
c++boostc++11variable-assignmentlist-initialization

Nesting Boost.Assignment `map_list_of`


Is it possible to change this C++11 initialization:

const std::map<int, std::map<int, std::string>> test =
  {{1,
    {{1, "bla"},
     {2, "blie"}
    }
   },
   {3,
    {{1, "ha"},
     {2, "hie"}
    }
   }
  };

To some form with Boost.Assignment without using temporaries? It does not seem possible to nest map_list_of in this way, unfortunately. Am I wrong?

Note: I am prepared for some terrible macros. As long as it works generally enough it would be fine. Variadic templates are not OK, as the target compiler is Intel C++ 2013 and/or MSVS2012.

EDIT: The "ideal" wrapper interface I would like to use looks something like this:

//header
extern const std::map<int, std::map<int, std::string>> test;

// source file
/*something*/ test
  /*something*/ 1,
  /*something*/ 1, "bla" /*something*/
  /*something*/ 2, "blie" /*something*/
  /*something*/ 2 //etc...

Where any /*something*/ can be empty. This should use both C++11 brace init or boost::assign::map_list_of. I am trying to avoid a manual repetition like here: https://stackoverflow.com/a/1872506/256138


Solution

  • It is possible to nest map_list_of in this manner, with hackery (but there may be temporaries created underneath, I'm unsure of that):

    #include <map>
    #include <string>
    #include <boost/assign/list_of.hpp>
    using boost::assign::map_list_of;
    
    const std::map<int, std::map<int, std::string> > test =
        map_list_of
            (1, map_list_of
                (1, "bla")
                (2, "blie")
                .convert_to_container<std::map<int, std::string> >()
            )
            (3, map_list_of
                (1, "ha")
                (2, "hie")
                .convert_to_container<std::map<int, std::string> >()
            )
        ;
    
    // Correctly prints "hie".
    //std::cout << test.find(3)->second.find(2)->second << "\n";
    

    Possible macro interface (ignoring the empty requirement, mainly because I am unsure what it means):

    #include <iostream>
    #include <string>
    #include <map>
    
    #ifdef CPP_11_AVAILABLE // Unsure what the actual macro is.
    #define map_entries_begin {
    #define map_entries_end }
    #define map_entry_begin {
    #define map_entry_end },
    
    #else
    #include <boost/assign/list_of.hpp>
    #define map_entries_begin boost::assign::map_list_of
    #define map_entries_end
    #define map_entry_begin (
    #define map_entry_end )
    
    #endif
    
    const std::map<int, std::map<int, std::string>> test =
        map_entries_begin
            //------//
            map_entry_begin
                1, map_entries_begin
                     map_entry_begin 1, "bla" map_entry_end
                     map_entry_begin 2, "blie" map_entry_end
                   map_entries_end
            map_entry_end
    
            //------//
            map_entry_begin
                3, map_entries_begin
                     map_entry_begin 1, "ha" map_entry_end
                     map_entry_begin 2, "hie" map_entry_end
                   map_entries_end
            map_entry_end
    
        map_entries_end;
    
    int main()
    {
        std::cout << test.find(3)->second.find(2)->second << "\n";
        return 0;
    }
    

    Admittedly quite verbose but seems to meet your requirement.

    See C++11 online demo at http://ideone.com/6Xx2t.