C++ has changed a lot in recent years. The last two revisions, C++11 and C++14, introduce so many new features that, in the words of Bjarne Stroustrup, “It feels like a new language.”
It’s true. Modern C++ lends itself to a whole new style of programming – and I couldn’t help noticing it has more of a Python flavor. Ranged-based for loops, type deduction, vector and map initializers, lambda expressions. The more you explore modern C++, the more you find Python’s fingerprints all over it.
Was Python a direct influence on modern C++? Or did Python simply adopt a few useful constructs before C++ got around to it? You be the judge.
Literals
Python introduced binary literals in 2008. Now C++14 has them. [Update: Thiago Macieira points out in the comments that GCC actually supported them back in 2007.]
static const int primes = 0b10100000100010100010100010101100;
Python also introduced raw string literals back in 1998. They’re convenient when hardcoding a regular expression or a Windows path. C++11 added the same idea with a slightly different syntax:
const char* path = R"(c:\this\string\has\backslashes)";
Range-Based For Loops
In Python, a for
loop always iterates over a Python object:
for x in myList: print(x)
Meanwhile, for nearly three decades, C++ supported only C-style for
loops. Finally, in C++11, range-based for loops were added:
for (int x : myList) std::cout << x;
You can iterate over a std::vector
or any class which implements the begin
and end
member functions – not unlike Python’s iterator protocol. With range-based for loops, I often find myself wishing C++ had Python’s xrange
function built-in.
Auto
Python has always been a dynamically typed language. You don’t need to declare variable types anywhere, since types are a property of the objects themselves.
x = "Hello world!"
print(x)
C++, on the other hand, is not dynamically typed. It’s statically typed. But since C++11 repurposedthe auto
keyword for type deduction, you can write code that looks a lot like dynamic typing:
auto x = "Hello world!"; std::cout << x;
When you call functions that are overloaded for several types, such as std::ostream::operator<<
or a template function, C++ resembles a dynamically typed language even more. C++14 further fleshes out support for the auto
keyword, adding support for auto
return values and auto
arguments to lambda functions.
Tuples
Python has had tuples pretty much since the beginning. They’re nice when you need to package several values together, but don’t feel like naming a class.
triple = (5, 6, 7) print(triple[0])
C++ added tuples to the standard library in C++11. The proposal even mentions Python as an inspiration:
auto triple = std::make_tuple(5, 6, 7); std::cout << std::get<0>(triple);
Python lets you unpack a tuple into separate variables:
x, y, z = triple
You can do the same thing in C++ using std::tie
:
std::tie(x, y, z) = triple;
Uniform Initialization
In Python, lists are a built-in type. As such, you can create a Python list using a single expression:
myList = [6, 3, 7, 8] myList.append(5);
C++’s std::vector
is the closest analog to a Python list. Uniform initialization, new in C++11, now lets us create them using a single expression as well:
auto myList = std::vector<int>{ 6, 3, 7, 8 }; myList.push_back(5);
In Python, you can also create a dictionary with a single expression:
myDict = {5: "foo", 6: "bar"} print(myDict[5])
Similarly, uniform initialization also works on C++’s std::map
and unordered_map
:
auto myDict = std::unordered_map<int, const char*>{ { 5, "foo" }, { 6, "bar" } }; std::cout << myDict[5];
Lambda Expressions
Python has supported lambda functions since 1994:
myList.sort(key = lambda x: abs(x))
Lambda expressions were added in C++11:
std::sort(myList.begin(), myList.end(), [](int x, int y){ return std::abs(x) < std::abs(y); });
In 2001, Python added statically nested scopes, which allow lambda functions to capture variables defined in enclosing functions:
def adder(amount): return lambda x: x + amount ... print(adder(5)(5))
Likewise, C++ lambda expressions support a flexible set of capture rules, allowing you to do similar things:
auto adder(int amount) { return [=](int x){ return x + amount; }; } ... std::cout << adder(5)(5);
Standard Algorithms
Python’s built-in filter
function lets you selectively copy elements from a list (though list comprehensions are preferred):
result = filter(lambda x: x >= 0, myList)
C++11 introduces std::copy_if
, which lets us use a similar, almost-functional style:
auto result = std::vector<int>{}; std::copy_if(myList.begin(), myList.end(), std::back_inserter(result), [](int x){ return x >= 0; });
Other C++ algorithms that mimic Python built-ins include transform
, any_of
, all_of
, min
and max
. The upcoming ranges proposal has the potential to simplify such expressions further.
Parameter Packs
Python began supporting arbitrary argument lists in 1998. You can define a function taking a variable number of arguments, exposed as a tuple, and expand a tuple when passing arguments to another function:
def foo(*args): return tuple(*args) ... triple = foo(5, 6, 7)
C++11 adds support for parameter packs. Unlike C-style variable arguments, but like Python’s arbitrary argument lists, the parameter pack has a name which represents the entire sequence of arguments. One important difference: C++ parameter packs are not exposed as a single object at runtime. You can only manipulate them through template metaprogramming at compile time.
template <typename... T> auto foo(T&&... args) { return std::make_tuple(args...); } ... auto triple = foo(5, 6, 7);
Not all of the new C++11 and C++14 features mimic Python functionality, but it seems a lot of them do. Python is recognized as a friendly, approachable programming language. Perhaps some of its charisma has rubbed off?
What do you think? Do the new features succeed in making C++ simpler, more approachable or more expressive?
Comments (29)
Patrice Roy· 6 days ago
A student of mine, a few years ago, remarked an interesting trend where, in his opinion, dynamic languages have a tendency to make their type systems more explicit (one could think of things such as TypeScript here, or some planned enhancements to JavaScript) while languages with static type systems have a tendency to offer syntax simplifications (auto, var, lambdas, etc.); he saw both «families» converging towards one another; I think he was onto something :)
Interesting post, as always. Cheers!
@minonne· 2 days ago
Francisco Lopes· 6 days ago
Martins· 6 days ago
R"(c:\this\string\has\backslashes)";
Jeff Preshing· 6 days ago
passerby· 6 days ago
Stan· 6 days ago
Guest· 5 days ago
fenbf· 6 days ago
basically you will be able to write: "for (elem : range)"
propsed for C++17
Budai· 6 days ago
Tom Lachecki· 6 days ago
Tom Lachecki· 6 days ago
fenbf· 5 days ago
I thought it would pass since it was even implemented in VS...
fabio· 6 days ago
Other languages usage of a certain feature is seldom viewed as more than a hint that a feature might be a good idea, most features are motivated by solving problems that were Identified. Individual feature authors and reviewers might however be influenced by other languages they know/like.
As far as language influence goes I would say that Haskell () is the strongest one, it keeps popping up as a reference during design discussions.
Python seems to be regarded as being good enough so that saying: "We should do x because Python does so" will not get you thrown from the room, unlike other languages I won't mention.
John· 6 days ago
Ted· 6 days ago
Catalin· 6 days ago
knivil· 5 days ago
jfcaron· 6 days ago
https://en.wikipedia.org/wiki/Greenspun%27s_tenth...
rightfold· 5 days ago
Lucidguppy· 5 days ago
hammonjj· 5 days ago
Jeff Preshing· 4 days ago
Thiago Macieira· 5 days ago
The text about variable arguments is a bit misleading. Variable arguments to functions in general have been supported in C since the dawn of time (remember printf). Variable arguments to macros have been available since C99 and GCC implemented them as an extension to C++ before C++11 standardised them. C++11 only added variable template parameters, which is just one of the aspects, albeit a very, very important one.
Jeff Preshing· 4 days ago
@teh· 4 days ago
@claudiordgz· 3 days ago
"What do you think? Do the new features succeed in making C++ simpler, more approachable or more expressive?"
Totally, the vector and map initializers are way beyond helpful. Plus the variadic templates are amazing and powerful tools.
Jochen· 1 day ago
olimp· 13 hours ago