Você está na página 1de 2

Why C++11 feels like a new

Language
For many of my colleagues and friends C++ is still a language of many mysteries,
complexities and not agile enough. Often, the Ruby collection API is referenced with
its more functional approach compared to C++ standard containers. And when
switching forth and back between Ruby, Python, Scala and C++, yes C++ may
sometimes feel a little bit dusty.
But not anymore, C++11 is here and brings a tons of new features that help to develop
the language in a better way and make it more modern. Well, yes, the process of
incrementally improving C++ is long and complex and takes exponentially more time
compared to smaller languages like Ruby, but there is progress.
But lets come back to the title: Why does C++11 feels like a new language? Because
you can! Not voting for a new president, but rather use lambdas everywhere giving
you the necessary freedom.
Lets consider the simple example of selecting items from a list of object that match a
certain criterion and then transform this list into a another list. Basically, all we want
to do is to use to functional programming paradigms fold and map. The
corresponding Ruby would look like this:
data.select {|user| user.level > 10}.collect {|user| user.name }

That looks nice and easy. Now what would the old C++ version probably look like:
std::vector<std::string> result;
for(std::vector<User>::const_iterator begin = data.begin(), end=data.end(); begin
!= end; ++begin) {
if (*begin.level > 10)
result.push_back(*begin.name);
}

It doesnt look that bad, but from a conceptual level it combines these two functions
into one. In addition, reusing this code block is almost impossible. But, can we write
this in a more idiomatic way for C++11?
auto fold = select(data, [](const User& u){ return u.level > 10; });
auto result = collect(fold, [](const User& u){ return u.name;});

That looks so much better and the best thing is that its not limited to vectors of Users,
but basically anything that accepts begin/end and provides an iterator interface. There
are two major components that we use from the standard library to implement the
select and collect functions: First of all lambdas. Omni-present in languages like
Scala and Ruby, under-valued in Python and anonymous classes in Java. Finally the
brave new world (wait is Lisp new?) arrived to C++ and lambdas are nothing more
than syntactic sugar around function objects why couldnt we have this earlier?
Now, that we have lambdas we basically use two functions from the standard library
copy_if and transform.To explain this, lets look at the implementation of select:
template<typename T, typename F>
auto select(const T& values, F func) -> T {
T result;
std::copy_if(std::begin(values), std::end(values),
std::back_inserter(result), func);
return result;
}

From the documentation, copy_if applies a function to a range and copies the current
value from source to destination if the function returns true. std::back_inserter is a

nice helper function that allows us to directly append a new values to a container
without having to manually code the push_back for the vector and is more agnostic to
the underlaying container.
Now, lets look at the collect implementation: This one would almost work exactly
like this in C++03 without the lambdas.
template <typename T, typename F>
auto collect(const T& values, F func) ->
std::vector<decltype(func(*std::begin(values)))> {
typedef std::vector<decltype(func(*std::begin(values)))> result_type;
result_type result(values.size());
std::transform(std::begin(values), std::end(values), std::begin(result), func);
return result;
}

While this looks weird in the beginning the definition of the return values for this
function is basically genius. decltype is a new operator in C++11 that evaluates an
expression at compile time to detect its type definition. In the above example, it will
evaluate to the return value of the function object that we supply. This means we can
write the complete definition of this function without ever knowing the return values
in advance but rather rely on lazy compile time evaluation. Awesome isnt it?
To summarize, the availability of operators like decltype and lambda expressions
allow writing much more concise code that better reflects the programmers intentions.
Never again must C++ coders hide when it comes to functional programming
paradigms.
https://medium.com/on-coding/af6b8d883c1d

Você também pode gostar