How do you initialize a map which takes a struct as value?

the kind of initialization we are using is introduced only in the emerging C++ standard called C++0x, hence the warning and the compiler option. Some compilers, as g++, already support some of the new features, but the standard itself is not yet accepted. It adds many new features to C++ as we know it. You can read more on Stroustrup's site.

to initialize the structure you can add a ctor (naturally), e.g.

struct category {
        category(int i, const std::string& n): id(i), name(n) {}
        int id;
        std::string name;
};

and then to initialize the map as follows:

categories[1] = category(1, "First category");

note that an implicit conversion from const char* to string will work here, or else you can define a ctor with const char* also.


In C++ (ISO/IEC 14882:2003), a brace enclosed list of expressions can be used to initialize a variable of aggregate type in the declaration that defines it.

E.g.

struct S { int a; std::string b; };

S x = { 39, "Hello, World\n" };

An aggregate type is an array or a class with no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions. Note that a class aggregate doesn't have to be a POD-class and any array is an aggregate whether or not the type that it is an array of is an aggregate.

However, a brace-enclosed list of expressions is only valid as an initializer for an aggregate, it is not generally allowed in other contexts such as assignment or a class constructor's member initialization list.

In the current draft of the next version of C++ (C++0x), a brace enclosed list of expressions (brace-init-list) is allowed in more contexts and when an object is initialized from such an initializer list it is called list-initialization.

New contexts where such a list is allowed include arguments in a function call, function returns, arguments to constructors, member and base initializers and on the right hand side of an assignment.

This means that this is not valid in C++03.

int main() {
        categories[1] = {1, "First category"};
        categories[2] = {2, "Second category"};
}

Instead you could do something like this.

int main() {
        category tmp1 = { 1, "First category" };
        category tmp2 = { 2, "Second category" };

        categories[1] = tmp1;
        categories[2] = tmp2;
}

Alternatively.

int main() {
        category tmpinit[] = { { 1, "First category" },
                               { 2, "Second category" } };
        categories[1] = tmpinit[0];
        categories[2] = tmpinit[1];
}

Or, you could consider making a factory function for your type. (You could add a constructor for your type but this would make your class a non-aggregate and would prevent you from using aggregate initialization in other places.)

category MakeCategory( int n, const char* s )
{
    category c = { n, s };
    return c;
}

int main()
{
    categories[1] = MakeCategory( 1, "First category" );
    categories[2] = MakeCategory( 2, "Second category" );
}

In the current C++ standard, you can use initializer lists to initialize arrays and structs containing POD values only. The next standard (aka C++0x or C++1x) will allow to do the same on structs containing non-POD types, e.g. std::string. That's what the warning is about.

I'd suggest you add a simple constructor to category that takes the id and name and simply call that constructor instead:

#include <map>
#include <string>

struct category {
        category() : id(0), name() {}
        category(int newId, std::string newName)
         : id(newId), name(newName) {}

        int id;
        std::string name;
};

std::map<int, category> categories;

int main() {
        categories[1] = category(1, "First category");
        categories[2] = category(2, "Second category");

}