Initializing a Static Std::Map≪Int, Int≫ in C++

C++14 Static class map initialization

You need to "define" your map after you "declared" it:
See: https://en.cppreference.com/w/cpp/language/static

#include <map>
#include <string>

struct SomeInfo
{
std::string id;
std::string name;
};

enum MyEnum {
Enum1, Enum2

};

class Foo
{
private:
static const std::map<MyEnum, SomeInfo> fooMap;
public:
static std::map<MyEnum, SomeInfo> getMap()
{
return fooMap;
}
};

const std::map<MyEnum, SomeInfo> Foo::fooMap = {
{MyEnum::Enum1, SomeInfo{ "info1", "Info 1" }},
{MyEnum::Enum2, SomeInfo{ "info2", "Info 2" }}
};


int main(){
auto val = Foo::getMap()[MyEnum::Enum1];
return 0;
}

And if you want to make your type not constructable you can delete the compiler generated default constructor via Foo() = delete; - it must not be private.

Initializing a static std::mapint, STRUCTURE in C++

I'd use Boost.Assignment :

#include <boost/assign/list_of.hpp>
...
/* no more temp1, temp2, or PluginDbArray */
...
PluginDB pluginDB = boost::assign::map_list_of
(1, PluginInfo(1, "Adder", ADDER))
(2, PluginInfo(2, "Multiplier", MULTIPLIER));

Initializing a static map using static members

I cannot reproduce this problem with GCC 6.1.0. However, it can be reproduced any time you try to bind a reference to a constexpr variable you haven't defined, which is probably what your std::map constructor does :

struct Foo {
static constexpr int i = 42;
};

int main() {
auto const &p = Foo::i; // undefined reference to `Foo::i'
}

This is because binding the reference is an ODR-use of i, which requires a unique definition to exist at link-time.

There is a simple workaround that works in most such cases, and that is to apply a unary +:

struct Foo {
static constexpr int i = 42;
};

int main() {
auto const &p = +Foo::i; // OK!
}

Applying + does not ODR-use i, since only its value is needed, not its identity. Then the reference binds to the temporary returned by +, instead of i.

Initializing a static std::mapint, unique_ptrint in C++

This is one possible implementation:

template <typename T, typename U>
class create_map
{
private:
std::map<T, U> m_map;
public:
create_map(T key, U val)
{
m_map.emplace(std::move(key), std::move(val));
}

create_map&& operator()(T key, U val) &&
{
m_map.emplace(std::move(key), std::move(val));
return std::move(*this);
}

operator std::map<T, U>() &&
{
return std::move(m_map);
}
};

Note the taking argument by value and then moving it into the map with emplace, and the conversion operator that moves from m_map.

I don't know if MSVC 2012 supports ref-qualifiers. If it doesn't, you'll need to remove it (that's the two &&s after the function parameter list). The point of that is to enforce that create_map should only be used as a temporary. It is possible to also enforce that the conversion operator is only called once, but I didn't do that in the code above.

Now your calls cannot use naked news because 1) it isn't exception-safe and 2) raw pointers cannot be implicitly converted to unique_ptrs. A simple make_unique implementation that doesn't take arrays into account is

namespace util {
template<class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}

You can then change the new MyField<DWORD>()s to util::make_unique<MyField<DWORD>>()*.

Demo.


* Using a qualified call disables ADL, which can have surprising effects when you upgrade your compiler if your call has arguments. A full implementation of make_unique according to the spec can be found in the example code in N3656, the make_unique proposal paper.

initialize part of a const std::map from another const std::map

While @Rakete111's answer is perfectly valid for what you need, I suggest elevating that to a function. Maybe you can use it multiple places.

std::map<int, std:::string> combine(std::map<int, std::string> const& map1,
std::map<int, std::string> const& map2)
{
std::map<int, std:::string> res(map1);
res.insert(map2.begin(), map2.end());
return res;
}

and then use

const auto secondMap = combine(firstMap,
std::map<int, std::string>{{3, "Third"}});

Initializing a static two dimensional mapint, int in C++

it would be:

map<int, map<int, int>> _map = {
{1, {{2, 100}, {3, 200}}}
};

You could also have:

_map[1] = {{2, 100}, {3, 200}};

Your snippet

map <int, map<int, int>> _map = {
{1, {{2, 100}}},
{1, {{3, 200}}}
};

would be "equivalent" (initialization versus insertion) to:

_map.insert({1, {{2, 100}}});
_map.insert({1, {{3, 200}}}); // Fails as key 1 already present.


Related Topics



Leave a reply



Submit