One of the more tedious things about STL containers is that you cannot easily initialise them, like you can a straight C array.
This is discussed a bit in this post:
For example, in C you can do this:
However you cannot do this, although you might want to:
I found a reasonably neat way of working around this, an adaptation of which I present here.
It involves deriving a class based on the container you want (eg. a vector<string> or a list<int>) and then overriding:
The code is below. The important part (which you can use in your own applications) is in bold, the rest is the example program.
The last part of the test program shows that you can still use the normal assignment of vectors (the base class assign) to copy one vector to another.
The only requirement for this to work is that the base class supports the push_back operation. Some containers (eg. maps) will not support that.
Output
Note, you cannot create and initialise the vector in a single line, like this:
This is because the compiler evaluates the expression after the "=" sign first, before creating the vector, and thus does not yet know that it has an operator comma. You need to split it into two lines, or at least, two statements, like this:
Credits
I got this idea from "Pretty Good Initialization Library" by Thorsten Ottosen, from the CodeProject web site:
That was apparently based on "InitUtil: An STL Container Initialization Library" by Leor Zolman, from this web site:
Personally I found those a bit long. The first one was 895 lines of code, and the second one 783 lines of code. If all you want to do is initialise a vector with a string of numbers, then my code presented here is only 36 lines of code. For maps of different things (eg. numbers keyed to a string) my code only takes 41 lines. The highly general approach may be an overkill in these situations.
The CodeProject one (the first one) also requires the Boost library to compile, which is even more code to install on your system, if you don't already have it.
However, you may find these approaches more general, more reliable, who knows? You can check them out if you want.
This is discussed a bit in this post:
http://www.gammon.com.au/forum/?bbsubject_id=2910
For example, in C you can do this:
char * mydata [] =
{
"The", "quick", "brown", "fox", "jumped", "over",
"the", "lazy", "dog"
};
However you cannot do this, although you might want to:
vector<string> mydata2 =
"The", "quick", "brown", "fox", "jumped", "over",
"the", "lazy", "dog";
I found a reasonably neat way of working around this, an adaptation of which I present here.
It involves deriving a class based on the container you want (eg. a vector<string> or a list<int>) and then overriding:
- operator=
This lets you assign the base type to the container (effectively replacing the container with a single element).
For example:
v = "apple";
Normally you cannot do that, because v is a container, and apple is not.
- operator,
This lets you assign a list of things to the container, by using the comma operator to push_back additional elements.
For example:
v = "apple", "orange", "pear";
What this does is start "v" with "apple", and then push_back "orange" and "pear" into it.
- operator+=
This lets you add to the container, by using the += operator to append to it. You can then use the comma operator to add even more items.
For example:
v += "banana", "pear", "mango";
What this does is append "banana" and then use the operator comma to also add "pear" and "mango".
The code is below. The important part (which you can use in your own applications) is in bold, the rest is the example program.
The last part of the test program shows that you can still use the normal assignment of vectors (the base class assign) to copy one vector to another.
The only requirement for this to work is that the base class supports the push_back operation. Some containers (eg. maps) will not support that.
// disable warnings about long names
#ifdef WIN32
#pragma warning( disable : 4786)
#endif
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
using namespace std;
// C is the container type (eg. vector)
template < typename C >
class init : public C
{
public:
// add to container (eg. v = 1, 2, 3; )
template <typename T>
init & operator, ( const T & value )
{
push_back (value);
return *this;
}
// append to container (eg. v += 4)
template <typename T>
init & operator+= ( const T & value )
{
push_back (value);
return *this;
}
// replace container (eg. v = 22)
template <typename T>
init & operator= ( const T & value )
{
clear ();
push_back (value);
return *this;
}
}; // end of class init
// general routine to show a container's contents
template <typename T>
void show (const string & prefix,
const T & container,
const char * delim = " ",
const string & suffix = "\n\n")
{
cout << prefix; // description
copy(container.begin(),
container.end(),
ostream_iterator<string>(cout, delim));
cout << suffix; // final description (eg. \n )
} // end of show
int main (void)
{
// vector of strings
init <vector<string> > v;
v = "The", "quick", "brown", "fox", "jumped", "over",
"the", "lazy", "dog";
show ("Vector ...\n", v);
vector<string> v2 (v);
show ("Copy ...\n", v2);
v += "and", "started", "running";
show ("After appending ...\n", v);
return 0;
} // end of main
Output
Vector ...
The quick brown fox jumped over the lazy dog
Copy ...
The quick brown fox jumped over the lazy dog
After appending ...
The quick brown fox jumped over the lazy dog and started running
Note, you cannot create and initialise the vector in a single line, like this:
init < vector<int> > v4 = 1, 2, 3, 4;
This is because the compiler evaluates the expression after the "=" sign first, before creating the vector, and thus does not yet know that it has an operator comma. You need to split it into two lines, or at least, two statements, like this:
init < vector<int> > v4;
v4 = 1, 2, 3, 4;
Credits
I got this idea from "Pretty Good Initialization Library" by Thorsten Ottosen, from the CodeProject web site:
http://www.codeproject.com/vcpp/stl/PGIL.asp
That was apparently based on "InitUtil: An STL Container Initialization Library" by Leor Zolman, from this web site:
http://www.bdsoft.com/tools/initutil.html
Personally I found those a bit long. The first one was 895 lines of code, and the second one 783 lines of code. If all you want to do is initialise a vector with a string of numbers, then my code presented here is only 36 lines of code. For maps of different things (eg. numbers keyed to a string) my code only takes 41 lines. The highly general approach may be an overkill in these situations.
The CodeProject one (the first one) also requires the Boost library to compile, which is even more code to install on your system, if you don't already have it.
However, you may find these approaches more general, more reliable, who knows? You can check them out if you want.