Initializing map of maps with initializer list in VS 2013
This is a known compiler bug, http://connect.microsoft.com/VisualStudio/feedback/details/800104/ . The compiler gets confused by temporaries in initializer lists, and can even destroy an individual object repeatedly. Because this is silent bad codegen, I've asked the compiler team to prioritize fixing this.
How to use std::map::operator= with initializer lists
You could construct a temporary and use it in the assignment.
std::map<int, char> m;
m = std::map<int, char>{{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};
If you don't want to repeat the type, you can use decltype
.
std::map<int, char> m;
m = decltype(m){{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};
Related SO posts:
- Initializing map of maps with initializer list in VS 2013
- Using Initializer Lists with std::map
- Is this a compiler bug? Am I doing something wrong?
Using Initializer Lists with std::map
At Slava's insistence, I worked with ctors to find an easy fix:
#include <map>
#include <string>
#include <iostream>
struct Params
{
int inputType;
std::string moduleName;
Params(const int n, const std::string& s) :
inputType(n),
moduleName(s)
{ }
};
int main()
{
std::map<std::string, Params> options = {
{ "Add", Params(30, "RecordLib" ) },
{ "Open", Params(40, "ViewLib" ) },
{ "Close", Params(50, "EditLib" ) },
{ "Inventory", Params(60, "ControlLib") },
{ "Report", Params(70, "ReportLib" ) }
};
for (const auto& pair : options)
{
std::cout << "Entry: " << pair.first << " ==> { " << pair.second.moduleName << " }" << std::endl;
}
return 0;
}
However, the original code should have worked, and apparently is an acknowledged bug by Microsoft.
Static const map initialization list with struct?
Visual Studio 2013 Update 2 has just fixed this bug.
Nested hash_map initilizer lists
There are numerous (well, at least 3) intrusive bugs related to initializer lists and uniform initialization in MSVC2013.
Update According to the comments, this particular bug was removed in VS13 Update 2.
Sadly, the advice is to... stay away from many of them for now. I keep the following rule in mind:
- on any type that has a constructor taking an initializer list (like all standard containers) always explicitly name the type (IOW don't use anonymous uniform initializer syntax)
Connect bugs:
https://connect.microsoft.com/VisualStudio/feedback/details/809243/c-11-initializer-lists-as-default-argument
https://connect.microsoft.com/VisualStudio/feedback/details/800364/initializer-list-calls-object-destructor-twice
- http://connect.microsoft.com/VisualStudio/feedback/details/800104/
For what it's worth, the following standard library code is fair game on gcc/clang: Live On Coliru
And here's how I'd recommend wording it for MSVC (I can't test it right now as I don't have a windows box handy):
#include <unordered_map>
enum ENUM1 { ENUM1_A, ENUM1_B };
enum ENUM2 { ENUM2_A, ENUM2_B };
enum ENUM3 { ENUM3_A, ENUM3_B };
namespace std {
template <> struct hash<ENUM1> : std::hash<int> {};
template <> struct hash<ENUM2> : std::hash<int> {};
template <> struct hash<ENUM3> : std::hash<int> {};
}
int main() {
using Map3 = std::unordered_map<ENUM3, int>;
using Map2 = std::unordered_map<ENUM2, Map3>;
std::unordered_map<ENUM1, Map2> A = {
{
ENUM1_A, Map2 {
{
ENUM2_A, Map3 {
{ ENUM3_A, 123 },
{ ENUM3_B, 45 },
},
},
{
ENUM2_B, Map3 {
{ ENUM3_A, 733 },
{ ENUM3_B, 413 },
}
}
}
}
};
}
Initializing a Map with List inside
No, they're not. Consider this:
Map<String, List<String>> keyToGroup = new HashMap<String, ArrayList<String>>();
keyToGroup.put("foo", new LinkedList<String>());
The second line is fine, because a LinkedList<String>
is a List<String>
- but it's not logically fine in terms of adding it to a HashMap<String, ArrayList<String>>
, because a LinkedList<String>
is not an ArrayList<String>
.
To make it clearer:
Map<String, ArrayList<String>> map1 = new HashMap<String, ArrayList<String>>();
Map<String, List<String>> map2 = map1; // This is invalid
map2.put("foo", new LinkedList<String>());
ArrayList<String> oops = map1.get("foo"); // Because this would be broken
This isn't just the case with collections as the type argument. It's even simpler to see with normal inheritance:
List<Banana> bunchOfBananas = new ArrayList<Banana>();
List<Fruit> fruitBowl = bunchOfBananas; // Invalid!
fruitBowl.add(new Apple());
Banana banana = bunchOfBananas.get(0);
Even though every banana is a fruit, so a "collection of bananas" is a "collection of fruit* in the sense of fetching them, not every fruit is a banana.
You can use wildcard parameterized types to help in some cases, but it depends on exactly what you're trying to achieve.
How can I initialize a std::map with comparison lambda by using an initializer list?
The constructor which takes an initializer list and a comparator is the following:
map( std::initializer_list<value_type> init,
const Compare& comp = Compare(),
const Allocator& alloc = Allocator() );
So you should write:
auto comp = [](int a, int b) { return b < a; };
std::map<int, int, decltype(comp)> m{{{5, 6}, {3, 4}, {1, 2}}, comp};
Related Topics
How Could I Sensibly Overload Placement Operator New
How to Do Password Authentication for a User Using Ldap
Checking for Duplicates in a Vector
Initialising Reference in Constructor C++
Is the Result of a Cast an Rvalue
Linux Executable Can't Find Shared Library in Same Folder
Why Is Std::For_Each a Non-Modifying Sequence Operation
Rotating a 2D Pixel Array by 90 Degrees
Qt - Qpushbutton Text Formatting
Why Are Override and Final Identifiers with Special Meaning Instead of Reserved Keywords
How to Compile: Unrecognized Relocation
How to Create a N Way Cartesian Product of Type Lists in C++
How to Know When a New Usb Storage Device Is Connected in Qt
What Is a Possible Workaround for Object Slicing in C++
Are There in X86 Any Instructions to Accelerate Sha (Sha1/2/256/512) Encoding
How to Compile a C++ Code in Gcc (G++) to See The Name Mangling on Overloaded Functions