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");
}