Initializing a static std::map<int, int> in C++ - c++

What is the right way of initializing a static map? Do we need a static function that will initialize it?

Using C++11:
#include <map>
using namespace std;
map<int, char> m = {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};
Using Boost.Assign:
#include <map>
#include "boost/assign.hpp"
using namespace std;
using namespace boost::assign;
map<int, char> m = map_list_of (1, 'a') (3, 'b') (5, 'c') (7, 'd');

Best way is to use a function:
#include <map>
using namespace std;
map<int,int> create_map()
{
map<int,int> m;
m[1] = 2;
m[3] = 4;
m[5] = 6;
return m;
}
map<int,int> m = create_map();

It's not a complicated issue to make something similar to boost. Here's a class with just three functions, including the constructor, to replicate what boost did (almost).
template <typename T, typename U>
class create_map
{
private:
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};
Usage:
std::map mymap = create_map<int, int >(1,2)(3,4)(5,6);
The above code works best for initialization of global variables or static members of a class which needs to be initialized and you have no idea when it gets used first but you want to assure that the values are available in it.
If say, you've got to insert elements into an existing std::map... here's another class for you.
template <typename MapType>
class map_add_values {
private:
MapType mMap;
public:
typedef typename MapType::key_type KeyType;
typedef typename MapType::mapped_type MappedType;
map_add_values(const KeyType& key, const MappedType& val)
{
mMap[key] = val;
}
map_add_values& operator()(const KeyType& key, const MappedType& val) {
mMap[key] = val;
return *this;
}
void to (MapType& map) {
map.insert(mMap.begin(), mMap.end());
}
};
Usage:
typedef std::map<int, int> Int2IntMap;
Int2IntMap testMap;
map_add_values<Int2IntMap>(1,2)(3,4)(5,6).to(testMap);
See it in action with GCC 4.7.2 here: http://ideone.com/3uYJiH
############### EVERYTHING BELOW THIS IS OBSOLETE #################
EDIT: The map_add_values class below, which was the original solution I had suggested, would fail when it comes to GCC 4.5+. Please look at the code above for how to add values to existing map.
template<typename T, typename U>
class map_add_values
{
private:
std::map<T,U>& m_map;
public:
map_add_values(std::map<T, U>& _map):m_map(_map){}
map_add_values& operator()(const T& _key, const U& _val)
{
m_map[key] = val;
return *this;
}
};
Usage:
std::map<int, int> my_map;
// Later somewhere along the code
map_add_values<int,int>(my_map)(1,2)(3,4)(5,6);
NOTE: Previously I used a operator [] for adding the actual values. This is not possible as commented by dalle.
##################### END OF OBSOLETE SECTION #####################

Here is another way that uses the 2-element data constructor. No functions are needed to initialize it. There is no 3rd party code (Boost), no static functions or objects, no tricks, just simple C++:
#include <map>
#include <string>
typedef std::map<std::string, int> MyMap;
const MyMap::value_type rawData[] = {
MyMap::value_type("hello", 42),
MyMap::value_type("world", 88),
};
const int numElems = sizeof rawData / sizeof rawData[0];
MyMap myMap(rawData, rawData + numElems);
Since I wrote this answer C++11 is out. You can now directly initialize STL containers using the new initializer list feature:
const MyMap myMap = { {"hello", 42}, {"world", 88} };

For example:
const std::map<LogLevel, const char*> g_log_levels_dsc =
{
{ LogLevel::Disabled, "[---]" },
{ LogLevel::Info, "[inf]" },
{ LogLevel::Warning, "[wrn]" },
{ LogLevel::Error, "[err]" },
{ LogLevel::Debug, "[dbg]" }
};
If map is a data member of a class, you can initialize it directly in header by the following way (since C++17):
// Example
template<>
class StringConverter<CacheMode> final
{
public:
static auto convert(CacheMode mode) -> const std::string&
{
// validate...
return s_modes.at(mode);
}
private:
static inline const std::map<CacheMode, std::string> s_modes =
{
{ CacheMode::All, "All" },
{ CacheMode::Selective, "Selective" },
{ CacheMode::None, "None" }
// etc
};
};

I would wrap the map inside a static object, and put the map initialisation code in the constructor of this object, this way you are sure the map is created before the initialisation code is executed.

Just wanted to share a pure C++ 98 work around:
#include <map>
std::map<std::string, std::string> aka;
struct akaInit
{
akaInit()
{
aka[ "George" ] = "John";
aka[ "Joe" ] = "Al";
aka[ "Phil" ] = "Sue";
aka[ "Smitty" ] = "Yando";
}
} AkaInit;

You can try:
std::map <int, int> mymap =
{
std::pair <int, int> (1, 1),
std::pair <int, int> (2, 2),
std::pair <int, int> (2, 2)
};

If you are stuck with C++98 and don't want to use boost, here there is the solution I use when I need to initialize a static map:
typedef std::pair< int, char > elemPair_t;
elemPair_t elemPairs[] =
{
elemPair_t( 1, 'a'),
elemPair_t( 3, 'b' ),
elemPair_t( 5, 'c' ),
elemPair_t( 7, 'd' )
};
const std::map< int, char > myMap( &elemPairs[ 0 ], &elemPairs[ sizeof( elemPairs ) / sizeof( elemPairs[ 0 ] ) ] );

This is similar to PierreBdR, without copying the map.
#include <map>
using namespace std;
bool create_map(map<int,int> &m)
{
m[1] = 2;
m[3] = 4;
m[5] = 6;
return true;
}
static map<int,int> m;
static bool _dummy = create_map (m);

In addition to the good top answer of using
const std::map<int, int> m = {{1,1},{4,2},{9,3},{16,4},{32,9}}
there's an additional possibility by directly calling a lambda that can be useful in a few cases:
const std::map<int, int> m = []()->auto {
std::map<int, int> m;
m[1]=1;
m[4]=2;
m[9]=3;
m[16]=4;
m[32]=9;
return m;
}();
Clearly a simple initializer list is better when writing this from scratch with literal values, but it does open up additional possibilities:
const std::map<int, int> m = []()->auto {
std::map<int, int> m;
for(int i=1;i<5;++i) m[i*i]=i;
m[32]=9;
return m;
}();
(Obviously it should be a normal function if you want to re-use it; and this does require recent C++.)

You have some very good answers here, but I'm to me, it looks like a case of "when all you know is a hammer"...
The simplest answer of to why there is no standard way to initialise a static map, is there is no good reason to ever use a static map...
A map is a structure designed for fast lookup, of an unknown set of elements. If you know the elements before hand, simply use a C-array. Enter the values in a sorted manner, or run sort on them, if you can't do this. You can then get log(n) performance by using the stl::functions to loop-up entries, lower_bound/upper_bound. When I have tested this previously they normally perform at least 4 times faster than a map.
The advantages are many fold...
- faster performance (*4, I've measured on many CPU's types, it's always around 4)
- simpler debugging. It's just easier to see what's going on with a linear layout.
- Trivial implementations of copy operations, should that become necessary.
- It allocates no memory at run time, so will never throw an exception.
- It's a standard interface, and so is very easy to share across, DLL's, or languages, etc.
I could go on, but if you want more, why not look at Stroustrup's many blogs on the subject.

Related

unordered_set<vector<int>> throws "Call to implicitly-deleted default constructor" error [duplicate]

Can I create a unordered_set of vectors in C++? something like this
std::unordered_set<std::vector<int>> s1;
because I know that is possible with the "set" class of the std lib but seems that it doesn't work for the unordered version
thanks
Update:
this is the exactly code that I'm trying to use
typedef int CustomerId;
typedef std::vector<CustomerId> Route;
typedef std::unordered_set<Route> Plan;
// ... in the main
Route r1 = { 4, 5, 2, 10 };
Route r2 = { 1, 3, 8 , 6 };
Route r3 = { 9, 7 };
Plan p = { r1, r2 };
and it's all right if I use set, but I receive a compilation error when try to use the unordered version
main.cpp:46:11: error: non-aggregate type 'Route' (aka 'vector<CustomerId>') cannot be initialized with an initializer list
Route r3 = { 9, 7 };
Sure you can. You'll have to come up with a hash though, since the default one (std::hash<std::vector<int>>) will not be implemented. For example, based on this answer, we can build:
struct VectorHash {
size_t operator()(const std::vector<int>& v) const {
std::hash<int> hasher;
size_t seed = 0;
for (int i : v) {
seed ^= hasher(i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
return seed;
}
};
And then:
using MySet = std::unordered_set<std::vector<int>, VectorHash>;
You could also, if you so choose, instead add a specialization to std::hash<T> for this type (note this could be undefined behavior with std::vector<int>, but is definitely okay with a user-defined type):
namespace std {
template <>
struct hash<std::vector<int>> {
size_t operator()(const vector<int>& v) const {
// same thing
}
};
}
using MySet = std::unordered_set<std::vector<int>>;
As an alternative to a custom-written hasher, Boost provides a hasher for many standard library types. This should work in your case:
#include <boost/container_hash/hash.hpp>
std::unordered_set<
std::vector<int>,
boost::hash<std::vector<int>>
> s1;
Reference: https://www.boost.org/doc/libs/1_78_0/doc/html/hash/reference.html
In older Boost versions, the header file was boost/functional/hash.hpp.

Initialize members of a class in C++

I have a class with the following declaration:
class OrderBook {
std::string OrderBookType;
std::map<double, vector<float*>> OrderBookData;
std::unordered_map<int, float*> OrderPool;
public:
OrderBook(string);
}
I have 2 questions regarding the class initialization:
I would like to specify the comparator for the OrderBook map based on OrderBookType.
Is the following valid/good programming practice?
OrderBook::OrderBook(string bookType) {
OrderBookType = bookType;
if (bookType == 'B') {
OrderBookData = std::map<float, vector<float*>, std::greater<float>>
}
else {
OrderBookData = std::map<float, vector<float*>, std::less<float>>
}
OrderPool;
}
How do I initialize an empty map for OrderPool? To make sure OrderPool is an empty unordered map, do I have to do the following:
OrderPool = std::unordered_map<int, float*>()
or is OrderPool; sufficient?
To 1.
No, it's not valid.
The types
std::map<float, vector<float*>, std::greater<float>>
and
std::map<float, vector<float*>, std::less<float>>
are different. You can't change the types at runtime.
IMHO the best approach is to create an own comparator that expects an argument and is passed to the constructor of the map (as mentionend in the comments of the question).
class Comp {
public:
Comp(bool greater) : g(greater) {}
bool operator()(double lhs, double rhs) const {
if (g) return lhs > rhs;
return lhs < rhs;
}
private:
bool g;
};
struct OrderBook {
std::string OrderBookType;
std::map<double, std::vector<float*>, Comp> OrderBookData;
std::unordered_map<int, float*> OrderPool;
public:
OrderBook(const std::string &);
};
OrderBook::OrderBook(const std::string &bookType) : OrderBookType(bookType), OrderBookData(Comp(bookType == "B")) {}
To 2.
std::unordered_map<int, float*> OrderPool; will be initialized as empty unordered map. The line
OrderPool;
does nothing.
You don't need to (and technically speaking you can't) initialize it again. If you want to clear the map you can use std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::clear
You could also create a new object and assign it with
OrderPool = std::unordered_map<int, float*>()
but I prefer
OrderPool.clear();

How to initialize a vector of vectors in pre c++ 11 syntax?

I've read a significant number of questions and answers on this exact topic but none of them have helped me figure this out.
I have a vector of vectors being initialized using c++ 11 code like so:
return { {1,1,1}, {1,2}, {2,1}, {3} };
How can I convert this to pre-c++ 11 syntax in as few lines as possible?
Assignment or construction from an array is a straightforward option:
int temp[] = { 1, 1, 1, 1, 2, 2, 1, 3 };
std::vector<std::vector<int>> a(4);
a[0].assign(&temp[0], &temp[3]);
a[1].assign(&temp[3], &temp[5]);
a[2].assign(&temp[5], &temp[7]);
a[3].assign(&temp[7], &temp[8]);
The basic code looks like this. Faster alternatives can avoid repeated calls to back(), but this is the clearest way to see how it relates to your original.
std::vector<std::vector<int>> a;
a.push_back(std::vector<int>());
a.back().push_back(1);
a.back().push_back(1);
a.back().push_back(1);
a.push_back(std::vector<int>());
a.back().push_back(1);
a.back().push_back(2);
a.push_back(std::vector<int>());
a.back().push_back(2);
a.back().push_back(1);
a.push_back(std::vector<int>());
a.back().push_back(3);
return a;
The key idea for writing maintainable code in C++03 (or C++98) is to name things. That's also a good idea in general, but it can conflict with ideal of reasonable conciseness. That is, it can easily become too verbose to be entirely painless.
With proper support one can then write code like
namespace my{
using std::vector;
vector< vector< int > >
foo()
{
int const a0[] = {1,1,1};
int const a1[] = {1,2};
int const a2[] = {2,1};
int const a3[] = {3};
typedef cppx::Array_range<int const> R;
R const ranges[] = {a0, a1, a2, a3};
return make_vecvec( ranges );
}
} // namespace my
Relevant support:
#include <iostream>
#include <stddef.h> // ptrdiff_t
#include <vector>
namespace cppx {
using std::vector;
typedef ptrdiff_t Size;
typedef Size Index;
template< class Item, Size n >
Size n_items( Item (&)[n] ) { return n; }
template< class Type >
struct Non_const{ typedef Type T; };
template< class Type >
struct Non_const< Type const > { typedef Type T; };
template< class Item >
struct Array_range
{
Item* const p_begin;
Item* const p_end;
template< Size n >
Array_range( Item (&a)[n] )
: p_begin( a )
, p_end( a + n )
{}
};
template< class Item, Size n >
vector<typename Non_const<Item>::T>
make_vec( Item (&a)[n] )
{
return vector<typename Non_const<Item>::T>( a, a + n );
}
template< class Item, Size n >
vector< vector< typename Non_const<Item>::T > >
make_vecvec( Array_range<Item> const (&a)[n] )
{
typedef typename Non_const<Item>::T Nc_item;
vector< vector< Nc_item > > result;
for( Index i = 0; i < n; ++i )
{
result.push_back( vector< Nc_item >(
a[i].p_begin, a[i].p_end
) );
}
return result;
}
} // namespace cppx
Disclaimer: (1) I just typed in the support code for this answer, fixing the direct const-ness issues I stumbled on. There are therefore probably reusability issues, but it shows the general idea (and it works). (2) I only compiled it with MinGW g++ (tdm64-1) 5.1.0.

Triple map including 2 keys

I have a structure containing 3 fields, two ints (let's call them A and B) and a bool (C).
I want to create a sort of array of that struct and be able to access it through any of the keys (A or B), getting the hole object (with A, B and C) in return.
I won't need to do something like "getting all the object for which the bool is true", if that makes any difference.
Obviously, both key are unique and the bool can't be, but I thought I'd mention it for the sake of clarity.
If there was no A or B, it would be a simple std::map<int, bool>.
The only solution I currently see is to make a wrapper containing 2 sets and a vector.
Is there any way to make my life easier?
NB: It will contain at most a hundred tuples, so performance should not be an issue. Linear access is acceptable.
To make it even clearer, here is what I'd like to be able to do:
foobar<int, int, bool> array; // or something along those lines
array.add(1, 101, true);
array.add(2, 102, false);
array.getA(1); // returns first object
array.getA(2); // returns second object
array.getB(102); // returns second object again
I believe what you're looking for is boost::multi_index. It'll allow you to declare a container with multiple indices.
struct MultiIDStruct
{
size_t idA;
size_t idB;
std::string name;
};
namespace mul = boost::multi_index;
boost::multi_index_container< MultiIDStruct,
mul::indexed_by<
mul::ordered_unique< mul::member< MultiIDStruct, size_t, &MultiIDStruct::idA > >,
mul::ordered_unique< mul::member< MultiIDStruct, size_t, &MultiIDStruct::idB > >
> > data;
(Used namespace "shortcut" as per Rapptz suggestion)
For example here you have a multi_index container of MultiIDStruct for which there are two unique orderings, one on idA (which is a member of MultiIDStruct) and a second on idB (which is also a member).
The template parameters seem like a handful at first but they're not so bad once you understand how they work.
The suggestion to split it up into two maps is certainly a bit simpler, but if you want some more flexibility and can use C++11 for features like std::tuple, you might try something of the form:
#include <iostream>
#include <map>
#include <tuple>
template <typename T1, typename T2, typename T3>
class foobar
{
public:
void add(T1 t1, T2 t2, T3 t3)
{
m1[t1] = std::make_tuple(t1, t2, t3);
m2[t2] = std::make_tuple(t1, t2, t3);
}
std::tuple<T1,T2,T3> getA(T1 t1)
{
return m1[t1];
}
std::tuple<T1,T2,T3> getB(T2 t2)
{
return m2[t2];
}
private:
std::map<T1,std::tuple<T1,T2,T3>> m1;
std::map<T2,std::tuple<T1,T2,T3>> m2;
};
int main()
{
foobar<int, int, bool> array; // or something along those lines
array.add(1, 101, true);
array.add(2, 102, false);
auto res1 = array.getA(1); // returns first object
auto res2 = array.getA(2); // returns second object
auto res3 = array.getB(102); // returns second object again
std::cout << std::get<0>(res1) << std::endl;
std::cout << std::get<1>(res2) << std::endl;
std::cout << std::get<2>(res3) << std::endl;
return 0;
}
A working example gives the output 1, 102, 0 (false).
I know I didn't give the detail implementation. But I'm just suggesting a logic with two maps. What's wrong with it? Why do I get downvoted?
struct s
{
int i;
int j;
bool b;
};
std::map<int, int> mapA;
std::map<int, s> mapB;
const s& getA(int i)
{
return mapB[mapA[i]];
}
const s& getB(int j)
{
return mapB[j];
}
void add(int i, int j, bool b)
{
s p;
p.i=i;
p.j=j;
p.b=b;
mapB[j]=p;
mapA[i]=j;
}
Having the same problem, and a different solution!
Have two hash functions on A and B, giving h1(A) and h2(B) such, that they do not give equal values. Example:
uint32_t A;
uint32_t B;
uint64_t hashA(uint32_t value)
{ return ((uint64_t)value) << 32; }
uint64_t hashB(uint32_t value)
{ return (uint64_t)value; }
Put all your stuff into std::map so that hashA and hashB have the same value for bool. Access it with either hashA or hashB.
Example: A = 0x10000001, B = 0x20000002, C = true
hashA(A): 0x1000000100000000
hashB(B): 0x0000000020000002
map:
0x1000000100000000 -> true
0x0000000020000002 -> true

How to combine a function and a predicate in for_each?

How can you call a Function over some part of a container, using for_each() ?
I have created a for_each_if() to do a
for( i in shapes )
if( i.color == 1 )
displayShape(i);
and the call looks like
for_each_if( shapes.begin(), shapes.end(),
bind2nd( ptr_fun(colorEquals), 0 ),
ptr_fun( displayShape ) );
bool colorEquals( Shape& s, int color ) {
return s.color == color;
}
However, I feel immitating STL-like algorithms is not something that I should be doing.
Is there a way to use only existing STL keywords to produce this ?
I did not want to do a
for_each( shapes.begin(), shapes.end(),
bind2nd( ptr_fun(display_shape_if_color_equals), 0 ) );
because, in a more complicated case, the functor name would be misleading with respect to what the functor
*Is there a way to access a struct's member (like colorEquals) for functions like for_each without having to create a function ? *
Imitating STL-like algorithms is exactly what you should be doing. That's why they're in the STL.
Specifically, you can use a functor instead of creating an actual function and binding it. This is much neater, really.
template<typename Iterator, typename Pred, typename Operation> void
for_each_if(Iterator begin, Iterator end, Pred p, Operation op) {
for(; begin != end; begin++) {
if (p(*begin)) {
op(*begin);
}
}
}
struct colorequals {
colorequals(int newcol) : color(newcol) {}
int color;
bool operator()(Shape& s) { return s.color == color; }
};
struct displayshape {
void operator()(Shape& s) { // display the shape }
};
for_each_if(shapes.begin(), shapes.end(), colorequals(0), displayshape());
This is usually considered the idiomatic way to go.
Using boost range adaptors is much neater.
using boost::adaptor::filtered;
using boost::bind;
class Shape {
int color() const;
};
void displayShape(const Shape & c);
bool test_color(const Shape & s, int color ){
return s.color() == color;
}
boost::for_each
( vec | filtered(bind(&test_color, _1, 1)
, bind(&displayShape, _1)
)
Note the use of the new range library to abstract away
iterators in favor of ranges and the range adaptors
library to compose a pipeline of operations.
All the standard stl iterator based algorithms have
been ported to range based algorithms.
Imagine this
typedef boost::unordered_map<int, std::string> Map;
Map map;
...
using boost::adaptor::map_keys;
using boost::bind
using boost::ref
using boost::adaptor::filtered;
bool gt(int a, int b)
{ return a > b };
std::string const & get(const Map & map, int const & a)
{ return map[a] }
// print all items from map whose key > 5
BOOST_FOREACH
( std::string const & s
, map
| map_keys
| filtered(bind(&gt, _1, 5))
| transformed(bind(&get, ref(map), _1))
)
{
cout << s;
}
Read Range Adaptors and Range Algorithm.
You can use the C++20 ranges. Here an example where we add one to all even numbers of a std::vector
#include <ranges>
#include <algorithm>
#include <vector>
namespace ranges = std::ranges;
std::vector<int> vec = {1, 2, 3, 4, 5};
const auto even = [](int i) { return 0 == i % 2; };
ranges::for_each(vec | std::views::filter(even), [](int& i){ i+=1;});
You can find a living example on compiler explorer here
To use a regular for_each with an if you would need a Functor that emulates an if condition.
#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
#include <boost/bind.hpp>
using namespace std;
struct incr {
typedef void result_type;
void operator()(int& i) { ++i; }
};
struct is_odd {
typedef bool return_type;
bool operator() (const int& value) {return (value%2)==1; }
};
template<class Fun, class Cond>
struct if_fun {
typedef void result_type;
void operator()(Fun fun, Cond cond, int& i) {
if(cond(i)) fun(i);
}
};
int main() {
vector<int> vec;
for(int i = 0; i < 10; ++i) vec.push_back(i);
for_each(vec.begin(), vec.end(), boost::bind(if_fun<incr, is_odd>(), incr(), is_odd(), _1));
for(vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
cout << *it << " ";
}
Unfortunately my template hackery isn't good enough to manage this with bind1st and bind2nd as it somehow gets confusing with the binder being returned being a unary_function but it looks pretty good with boost::bind anyhow. My example is no means perfect as it doesn't allow the Func passed into if_fun to return and I guess somebody could point out more flaws. Suggestions are welcome.