pythonic c++03

intro

A lot of people have noticed that c++ is moving towards 'pythonic' style last years.
All that new c++11 and c++14 features allows a way different style of programming.
I will try to show how can you achieve a nice 'pythonic' programming style with c++03 and boost.

list comprehensions

A nice feature is list comprehensions and slicing.

validItems = [i for i in self.getSomeItems()[1:10] if i.isValid()]

Now lets try to recreate this with c++ and boost::range.

#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>

std::vector<boost::shared_ptr<Item> > validItems;
boost::copy(validItems
            | boost::adaptors::sliced(1, 10)
            | boost::adaptors::filtered(boost::bind(&Item::isValid, _1)),
            std::back_inserter(validItems));

string formatting

We will use boost::format library to recreate a limited subset of python formatting.
So here goes python

s = '%s and %s' % ('tom', 'jerry')

Alternative in c++

#include <boost/format.hpp>
std::string s = boost::str(boost::format("%1% and %2%") % "tom" % "jerry");

But we still can't do stuff like this in c++:

s = '%(one)s and %(two)s' % {'one': 'tom', 'two': 'jerry'}

inplace collections

We will solve this one with boost::assign
Python code

l = [1, 2, 3, 4]
s = set([1, 2, 3, 4])
m = {'a':1, 'b': 2}

And in c++

#include <boost/assign.hpp>
std::list<int> l = boost::assign::list_of(1)(2)(3)(4);
std::set<int> s = boost::assign::list_of(1)(2)(3)(4);
std::map<std::string, int> m = boost::assign::map_list_of("a", 1)("b", 2);

foreach

Just use boost::foreach and boost::range::adaptors

for x in [1, 2, 3, 4]:
    print x
for x in [normalize(i) for i in [1, 2, 3, 4]]:
    print x
for x in mydict.values():
    print x

Here goes c++

#include <boost/foreach.hpp>
BOOST_FOREACH (int x, boost::assign::list_of(1)(2)(3)(4)) {
  std::cout << x;
}
BOOST_FOREACH (int x, boost::assign::list_of(1)(2)(3)(4)
                      | boost::adaptors::transformed(boost::bind(&normalize, _1))) {
  std::cout << x;
}
BOOST_FOREACH (int x, mymap | boost::adaptors::map_values) {
  std::cout << x;
}

lambdas

Yes, there are real lambdas starting from c++11. But lets see what can we do in C++03.
As you know there are a lot of limitations on lambda expressions in python.
So in python you can do only one liners.

In c++03 and boost you have a lot of options for this. You can use next libraries: boost::bind, boost::phoenix, boost::lambda.

Lets start from the most obvious one - bind.

boost::bind

python:

s = filter(lambda x: x.value % 2 == 0, [A(1), A(2), A(3)])

cpp:

#include <boost/range/algorithm.hpp>
#include <boost/bind.hpp>
std::list<int> s;
boost::copy_if(boost::assign::list_of(A(1))(A(2))(A(3)), std::back_inserter(s),
               boost::bind(&A::value, _1) % 2 == 0);

boost::lambda

python:

valid = [x for x in objects if x is not None]

c++:

#include <boost/lambda/lambda.hpp>
#include <boost/range/algorithm.hpp>
std::vector<boost::shared_ptr<Object> > valid;
boost::copy(objs | boost::range::filtered(boost::lambda::_1),
            std::back_inserter(valid));

boost::phoenix

To be done. I am not active user of this.

string operations

Operations like split and join are very usefull and can be performed very easily in python

"1, 2, 3, 4".split(",")
",".join([str(x) for x in [1, 2, 3, 4]])

And c++ equivalent will use boost::algorithm::string, boost::assign and boost::lexical_cast

#include <boost/lexical_cast.hpp>
#include <boost/string/algorithm.hpp>
std::vector<std::string> splitted;
boost::split(std::string("1, 2, 3, 4"), std::back_inserter(splitted), boost::is_any_of(","));
//
boost::join(boost::assign::list_of(1)(2)(3)(4)
            | boost::adaptors::transformed(boost::bind(&boost::lexical_cast<std::string, int>, _1)), ",");

tuples

Here is all simple. You can use boost::tuple for generic case. And std::pair for cases when you need tuple with 2 elements.
python version

[("earth", 10, 20.13),
 ("venus", 13, 12.86),
 ("mars", 15, 0.12)]

And c++

#include <boost/tuple/tuple.hpp>
boost::assign::list_of
(boost::tuple<std::string, int, double>("earth", 10, 20.13))
(boost::tuple<std::string, int, double>("venus", 13, 12.86))
(boost::tuple<std::string, int, double>("mars", 15, 0.12))