I was wondering if this was possible, and if so how I'd go about doing so. If it's not possible I'll just have to add the elements during the constructor body.
Ideally I would like the map immutable after construction.
What I'm trying to achieve is adding two pairs to the map that are created from constructor parameters.
It's possible, by copy construction: invoke a function which build the map!
std::map<int,int> myFunc(int a, int b);
class MyObject
{
public:
MyObject(int a, int b): m_map(myFunc(a,b)) {}
private:
std::map<int,int> m_map;
};
Without extra tools you can only init std containers in initialization lists as far as their constructors support you. If you need more, map_list_of()
et al from Boost.Assign do a great job.
Boost.Assign in action:
class C
{
const std::map<int,int> _vi;
public:
C() : _vi(boost::assign::map_list_of(1,1)(2,1)(3,2)) {}
}
edit: updated to std::map
example.
There’s a map constructor that takes a range as a pair of iterators. Using that, you can construct something similar to your demands:
pair<int, int> init[] = { make_pair(1, 2), make_pair(2, 3) };
map<int, int> const mymap(init, init + 2);
Granted, not pretty.
The next version of C++ will come with better support for initialization lists. Until then, Boost.Assign is the next best thing.
I use an initializer class:
template<class K, class V>
class MapInitializer
{
std::map<K,V> m;
public:
operator std::map<K,V>() const
{
return m;
}
MapInitializer& Add( const K& k, const V& v )
{
m[ k ] = v;
return *this;
}
};
Then to put it to use:
class C
{
const std::map<int,const char*> m_map;
public:
C() : m_map( MapInitializer<int,const char*>()
.Add( 1, "Hi there" )
.Add( 2, "In the middle" )
.Add( 9, "Goodbye" ) )
{}
};
This is free (in the sense that you aren't building a map, copying it, and throwing the first away) because of C++'s return value optimization. The same thing can be done for initializing a vector or other standard containers.
Hope that helps!