Useful Tools When Testing And Prototyping
In everyday life as a programmer, I often need to quick testing. Situations arise such as testing an STL algorithm (because I am not sure how it behave, want to have a better understanding and so on), or testing my own algorithm. This means that I need to create container and give some initial values. Sometimes I need to do it in hurry or when I have some spare times. STL doesn’t provide helpers to create and initialize quickly a container of different type. For example, to initialize a vector with some values I need to write a set of “push_pack()”. To initialize a map I need to insert a pair, this is not handy. Recently I started to use the “Boost Assign Library”. It’s just a great library which provides a set of helper functions to initialize container quickly without using method such as “push_back()”, “insert()”, and so on) and make your everyday life as programmer a lot easier.
To use the library, include the “boost/assign/” header. If the assign related functions are needed, include
// boost assign library header #include <boost/assign/list_of.hpp> // list_of() to scope #include <boost/assign/ptr_list_of.hpp> // ptr_list_of #include <boost/assign/ptr_list_inserter.hpp> // for ‘ptr_push_back()’, ‘ptr_insert()’ #include <boost/assign/std/vector.hpp> // for ‘operator+=()’ |
operator +=
Different type of initialization, the first one that i present is the “operator +=”, in which you can assign in a list format the initial values. Let’s say that I want to test some algorithm from boost range library. I need to create a vector and then initialize it
using namespace boost::adaptors;using namespace boost::assign;
// vector (list-initializer) std::vector<int> w_vec;w_vec += 1,2,3,4,5,6,7,8,9; // initialize function from lambda expression std::function<int(int)> func = [](int i) { return –i; }; // find the minimum element of the range std::cout << *boost::min_element(w_vec | boost::adaptors::transformed(func) ) << std::endl; |
In one line of code the vector is initialized. It is clear and readable. I know, with C++11 we have the new feature call list initializer, but it is not supported by every compiler. Since I am working with VC++ 2012, this functionality is not supported yet (I think it is supported in VC++2013). For the rest of code snippet I am just computing the minimum value of the range by using the boost range algorithm coupled with a range adaptor (transformed adaptor, which accept a function that negate all element of the collection before taking the minimum value).
A few words about these 2 boost libraries (range algorithm and adaptor). It’s just great tools that really simplify programmer’s life and make you more efficient!! To make it more compact we use the lambda function as the argument of the transformed adaptor
// calculate the minimum element of the collection std::cout << *boost::min_element( w_vec | boost::adaptors::transformed([](int i) {return -i;};) ) << std::endl; |
You go through the whole collection (no loop), negate all elements and return the minimum value and by writing only one line of code!!! Could it be more concise? If so, I just don’t see it. Moreover the code is clear; there is no doubt about what we are doing. Boost version of “min_element” accept a range, no more begin() and end() to specify the range extent, you just pass the whole range and use operator “|” to customize the algorithm with adaptors. In a testing context where you want to prototype something quickly, this is the tool that you need. I discover the adaptor library recently and just started to use it, it is so helpful and fill an important requirement, modifying values of a container on-the-fly. The syntax is clear and so easy to use. Range adaptors really simplify programmer’s life. Most of the times when you test, you want to check or even better modify it on-the-fly result and that what boost adaptor provides.
Boost adaptors and assign library both together gives you a set of powerful tools to test, prototype very fast.
Below I present some other initialization of the Boost Assign Library. There is a lot more, but I won’t review all of them. I just want to point out that there are tools that can help you in your everyday task, that make you more efficient and finally write better code.
list_of()
A class for our test
struct testAssign {
testAssign(): m_intVal(0), m_floatVal(0.f) {} explicit testAssign(int aint, float afloat=1.f) : m_intVal(aint), m_floatVal(afloat) { std::cout << “We are in the conversion ctor\n”;} int m_intVal; float m_floatVal;}; |
You can initialize a list of user defined type in a very nice manner (quick). Below a test class which has 2 constructor, default and a conversion ctor. Instead of using the “push_back()” method to fill a vector, you simply use the ‘list_of()’ of the assign library and initialize the type by calling directly ctor. The main advantage of using such initialization, it’s the compact syntax for initializing the type (just need to specify ctor arguments or empty parenthesis for default ctor).
void testListOf(){
using namespace boost; using namespacboost::assign; std::vector<testAssign>w_vecAssign; w_vecAssign=list_of<testAssign>(1,3.f)(2,2.4f); //conversion ctor for (testAssign w_assign : w_vecAssign) { std::cout << “Integer value is: “ << w_assign.m_intVal << “\n”; std::cout << “Floating value is: “ << w_assign.m_floatVal << “\n”; } std::vector<testAssign> w_vecAssign1; w_vecAssign1=list_of<testAssign>()()(); // default ctor } |
Initializing a vector of vector (matrix notation) it’s very painful when you have to do it by hand. Can use the assign to initialize a matrix, it’s very easy by using nested “list_of”. Let’s take a look at this example here we put values into an object of type std::vector<std::vector<int>>
void test_vector_matrix(){
using namespace boost; using namespace boost::assign; std::vector<std::vector<int>> w_matrix; w_matrix += list_of(1)(2)(4), // first row list_of(3)(1)(2), // second row list_of(5)(6)(7); // 3X3 matrix // now printing each row of the matrix BOOST_FOREACH( const std::vector<int> &aRow, w_matrix) { // print each row of the matrix boost::copy( aRow, std::ostream_iterator<int>( std::cout,” “)); std::cout << std::endl; } } |
pair_list_of
In the same manner as the ‘list_of’, there is the ‘pair_list_of’. Below a code snippet that shows initialization of a vector of pair, and then print the element (for example key of the pair). There is also a ‘tuple_list_of’ which I don’t present here, but it’s exactly the same. Also I show an example of using the ‘list_of’ to initialize the pair element.
void pairtupleInit() {
using namespace boost::assign; typedef std::pair<int, int> Pair; std::vector<Pair> vecPair; vecPair=pair_list_of(1,2)(2,3); auto first = std::bind( &Pair::first, std::placeholders::_1); std::vector<int/*key*/> vecofkeys; std::transform( std::begin(vecPair),std::end(vecPair), std::back_inserter(vecofkeys),first); // print pair key element boost::copy( vecofkeys, std::ostream_iterator<int>(std::cout,“”)); // we could use the ‘list_of’, but notation is not as // compact as the ‘pair_list_of’. We need to call the // utility “make_pair” to initialize pair element. std::vector<Pair> v_pair = list_of<Pair>( std::make_pair(1,2)) (std::make_pair(2,3)); for( auto& first : v_pair | boost::adaptors::map_keys) { std::cout << first << ” “; } } |
ptr_push_back()
For pointer container similar functions are available to initialize for example boost pointer vector. A few words about the boost pointer vector. ‘ptr-vector’ is one of the pointer container of the boost pointer container library. It’s a wrapper for standard vector<T*> that cuts one level of indirection for iterators and member functions. In essence, ‘ptr_vector’ lets you treat of vector of pointers as if it were a vector of values.
In the code snippet below we create a pointer vector and initialize it with the helper ‘push_back_of’. Notice how instance are created, we pass as argument the container and then call ctor by using the parenthesis, don’t need to call new manually. Actually, ‘ptr_push_of’ return a proxy that overloads the operator (). I really like this syntax, because it’s short and handy, just need to list all instance of the pointer element to fill the vector.
void ptrInit() {
using namespace boost; using namespace boost::assign; // pushing abstract type (derived from) ptr_vector<testAssign> w_ptrVecInt; ptr_push_back<testAssign>(w_ptrVecInt)(1)(3); for( const testAssign& aObj : w_ptrVecInt) { // print information about the object std::cout << “Value is: “ << aObj.m_intVal << “\n”; } } |
We can also use the ‘push_back_ptr” with standard container (vector of pointer). Problem with standard container of pointer, there is no automatic deletion when container goes out of scope. I use the for_each algorithm in combination with anonymous function (new features of C++11) for the clean-up, deletion of each object manually. By using the boost pointer container you don’t have to manage the deletion of the container, it’s done automatically. Could use the std::unique<T> smart pointer container.
// you can create a std pointer containervoid testStdPtrVec()
{ using namespace boost; using namespace boost::assign; // ptr_xx helper with standard container std::vector<testAssign*> w_stdptrVec; ptr_push_back<testAssign>( w_stdptrVec)(1)(2); for( testAssign* aObj : w_stdptrVec) { // print information about the object std::cout << “Value is: “ << aObj->m_intVal << “\n”; } // cleaned up before we go out of scope for_each( w_stdptrVec.begin(), w_stdptrVec.end(), []( testAssign*& aPtr2Obj) { // anonymous function std::cout << “Deleting object\n”; delete aPtr2Obj; aPtr2Obj=nullptr;} ); } |
Below an abstract class and a derived class inherited from base class. Notice that the base class inherits from the boost::noncopyable. What that’s means? That’s the copy and assignment constructor are private, and not accessible from client side. It’s part of the Boost operator library.
// Abstract base classclass AbstractClass : private boost::noncopyable
{ public:AbstractClass() { std::cout << “Base class default ctor\n”;} virtual ~AbstractClass() { std::cout << “Virtual Base class dtor\n”;} // class method void baseImpl() { std::cout << “We are in the Base implementation\n”;} // abstract method virtual void methodAbs()=0; private: }; // inherited class class Derived : public AbstractClass { public: Derived() : AbstractClass(), m_int(0) {} explicit Derived( int aInt) : m_int(aInt) {/*conversion ctor*/} ~Derived() { std::cout << “Derived class dtor\n”;} void methodAbs() override final { std::cout << “Base lass method overided\n”;} void methodAbs() const { std::cout << “Deriv1 class const version method\n”;} private: int m_int; }; |
Finally we create a pointer container of polymorphic type. The code snippet shows how to do it in a simple case, then through base reference call polymorphic method.
void testPolyType(){
using namespace boost; using namespace boost::assign; // vector of abstract base class ptr_vector<AbstractClass> w_ptrvec(5); // push derived class (polymorphic type) ptr_push_back<Derived>(w_ptrvec)()(2)(3)(23)(); for( AbstractClass& w_absClass : w_ptrvec) { // polymorphic method call through base reference w_absClass.methodAbs(); // base class overriden method } } |
Conclusion
There are a few more utilities included with boost::assign, which might be of lesser uses. The library can even be extended to non-standard containers if the need should arise. But just with the main ones I just mentioned in this post, I can see my handling of containers is going to be drastically different from now on. I keep finding more and more places to use it. I’m also contemplating in abandoning my old static const pure array (with assert on array length) for all those small local tables of data. Replacing them with static std:vectors initialized with a ‘list_of’ seems a much safer way to go from now on.
Leave a Reply
Want to join the discussion?Feel free to contribute!