Several boost libraries are inspired by python and C++11 features all help to write C++ code that is surprisingly similar to python, with a bit of extra type sepcification. If you think otherwise I'd suggest you're probably thinking of the C++ of the 90s - a more C with classes, and not modern C++.
I often find it useful to develop and prototype in python and convert to C++. Most often I'm doing this because my python simulations can take days and the C++ versions hours. Often I find it is not just the performance critical areas, but it is easy enough just to wholesale convert the lot.
I agree, especially with C++11 and (besides Boost) Qt. It's often the header/code separation that makes things a bit tedious, having to keep function and method signatures in-sync. Of course, if you are template-land that is not that much of a problem.
We're also replacing core op-graph and geometry processing from Python to C++, and again it's close to 1-1 - there's a bit of overhead in the loops - in our coding style we're caching begin iterators on the line before the loop, but other than that it's very close.
And the speed of the app is so much faster it's not even funny.
Can you give an example of what this looks like?
python:
for face in mesh.faces():
faceCentre = Point()
for v in face.vertices():
faceCentre.add(mesh.getPoint(v))
faceCentre.div(len(face.vertices()))
C++:
std::vector<Face>::const_iterator itFace = mesh.getFaces().begin();
for (; itFace != mesh.getFaces().end(); ++itFace)
{
const Face& face = *itFace;
Point faceCentre;
std::vector<unsigned int>::const_iterator itVertex = face.vertices.begin();
for (; itVertex != face.vertices().end(); ++itVertex)
{
const unsigned int& pointIndex = *itVertex;
faceCentre += mesh.getPoint(pointIndex);
}
faceCentre /= (float)face.vertices().size();
}
So the C++ is longer, but you've got braces, and the references to the Face and unsigned int pointIndex are placed as a local variables, which makes debugging much easier - they could be inlined.It's possible to get that down even more using more modern C++ - using auto variables and not declaring the start iterator on it's own line.
So yes, counting braces, it can be a lot more lines, but if you don't count braces, it's generally not that much more.
Also, as of C++11 you can do this:
for(const Face& face : mesh.getFaces()) {
Point faceCentre;
for(size_t pointIndex : face.vertices())
faceCentre += mesh.getPoint(pointIndex);
faceCentre /= static_cast<float>(face.vertices().size());
}We sometimes hoist the end iterator as well, as often g++ can't optimise out the call to .end() each iteration - it can if there's a ref to a const item and you call end() on that const ref, but otherwise, it generally doesn't as it can't guarantee the item hasn't been modified.
We're still stuck with CentOS 5.4, so g++ 4.1 for us as that's what we've got to deploy to (although we use ICC for production builds, building off the g++ 4.1 standard headers)...
Basically, we want top possible speed - if that means the code's a bit more verbose than it can be, so be it.
And just look at the difference in readability/simplicity. I can explain the Python code to my 12 year-old cousin, the C++ version though...