Functional in C++17 and C++20
Which functional feature can we expect with C++17, and for which functional feature can we hope with C++20? This is precisely the question I will concisely answer in this post.
With C++17 we get fold expressions and the new container std::optional. Even more thrilling becomes C++20. Concepts, the ranges library, and improved futures support new concepts in C++.
At first, to the near future. I will start in the next post with my systematic description of functional programming in C++. Therefore, I will be concise in this post. This post is only intended to make you more appetite.
C++17
Fold expressions
C++11 has Variadic Templates. These are templates that can get an arbitrary number of arguments. The arbitrary number is bound in a parameter pack. New is with C++17 that you can directly reduce a parameter pack with a binary operator. Therefore, you can directly implement Haskell’s function family foldl, foldr, foldl1, and foldr1, which reduce a list to a value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// foldExpression.cpp #include <iostream> template<typename... Args> bool all(Args... args) { return (... && args); } template<typename... Args> bool any(Args... args) { return (... || args); } template<typename... Args> bool none(Args... args) { return not(... || args); } int main(){ std::cout << std::endl; std::cout << std::boolalpha; std::cout << "all(true): " << all(true) << std::endl; std::cout << "any(true): " << any(true) << std::endl; std::cout << "none(true): " << none(true) << std::endl; std::cout << std::endl; std::cout << "all(true, true, true, false): " << all(true, true, true, false) << std::endl; std::cout << "any(true, true, true, false): " << any(true, true, true, false) << std::endl; std::cout << "none(true, true, true, false): " << none(true, true, true, false) << std::endl; std::cout << std::endl; std::cout << "all(false, false, false, false): " << all(false, false, false, false) << std::endl; std::cout << "any(false, false, false, false): " << any(false, false, false, false) << std::endl; std::cout << "none(false, false, false, false): " << none(false, false, false, false) << std::endl; std::cout << std::endl; } |
The function templates all, any, and none return at compile-time true, or false. I will have a closer look at the function template any in lines 5 and 6. The parameter pack (…) is unpacked on the binary operator (… && args). The three dots define (ellipse) the parameter pack.
For the program’s output, I use the online compiler on cppreference.com.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
Haskell has the maybe monad, and C++17 will get std::optional.
std::optional
std::optional stands for a calculation that maybe have a value. A find algorithm or a query of a hash table must deal with the fact that no value is available. Often, you use special values to indicate that you get no result. In short, a non-results. Often null pointers, empty strings, or special integer values are used for non-results. This is inconvenient and error-prone because you have to deal especially with non-result, and you have to distinguish the non-result from a regular result. In case of a non-result, you get with std::optional no value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// optional.cpp #include <experimental/optional> #include <iostream> #include <vector> std::experimental::optional<int> getFirst(const std::vector<int>& vec){ if ( !vec.empty() ) return std::experimental::optional<int>(vec[0]); else return std::experimental::optional<int>(); } int main(){ std::vector<int> myVec{1,2,3}; std::vector<int> myEmptyVec; auto myInt= getFirst(myVec); if (myInt){ std::cout << "*myInt: " << *myInt << std::endl; std::cout << "myInt.value(): " << myInt.value() << std::endl; std::cout << "myInt.value_or(2017):" << myInt.value_or(2017) << std::endl; } std::cout << std::endl; auto myEmptyInt= getFirst(myEmptyVec); if (!myEmptyInt){ std::cout << "myEmptyInt.value_or(2017):" << myEmptyInt.value_or(2017) << std::endl; } } |
std::optional is currently in the namespace experimental. That will change with C++17. If it exists, the function getFirst will return the first element (line 8). If not, a std::optional<int> object. I use in the main function two vectors. The calls getFirst in lines 17 and 27 return a std::optional object. In the case of myInt (line 19), the object has a value; in the case of myEmptyInt (line 29), no value. Now, I can display the value of myInt (lines 20 – 22). The method value_or in lines 22 and 30 will return a value if std::optional-object has a value if not a default value.
The impact of functional programming in C++ – particularly Haskell – increases significantly with C++20. Of course, it’s a little bit risky to predict C++20. I made a mistake once and said that the following features are part of C++17, which is, of course, not true.
C++20
Promised, the details of concepts, the ranges library, and the improved futures will follow in future posts.
Concepts
Type classes in Haskell are interfaces for similar types. If a type is a member of a type class, it will have specific properties. Type classes play in generic programming a similar role as interfaces in object-oriented programming. Inspired by type classes, you can specify requirements for the template parameters. The new functionality has the name concepts. For example, the sort algorithm requires that a template argument be sorted.
template<typename Cont> requires Sortable<Cont>() void sort(Cont& container){...}
What are the benefits of concepts? At first, the template declaration states which properties must hold for the template arguments. Therefore, the compiler can detect the break of the contract and display an unambiguous error message.
std::list<int> lst = {1998,2014,2003,2011}; sort(lst); // ERROR: lst is no random-access container with <
The C++ community waits at least as eagerly for concepts as for the new ranges library from Eric Niebler.
Ranges library
From the birds-eye perspective, the ranges library empowers you to apply the Standard Template Library algorithms directly on the whole container. But under the hood, we get new programming techniques.
- Lazy evaluation that enables you to apply the algorithm on infinite data streams.
- Thanks to the pipe symbol, we get function composition.
- Thanks to Range comprehension, you can directly create ranges similar to list comprehension in Python or Haskell.
1 2 3 4 |
auto odds= view::transform([](int i){ return i*i; }) | view::remove_if([](int i){ return i % 2 == 0; }) | view::take_while([](int i){ return i < 1000; }); auto oddNumbers= view::ints(1) | odds; |
oddNumbers holds, as a result, the square of all odd numbers smaller than 1000: 1, 9, 25, …, 841, 961. How does it work? The function composition calculates at first to each number is square (line 1), removes all even numbers (line 2), and stops if the square of numbers is greater than 1000 (line 3). I use odds in line number 4. view::int(1) creates the infinite input stream of integers starting with 0. Odds will stop the input stream.
There is proposal n3721 for the improvement of futures. The main issue with C++11 futures is that you can not compose them. C++20 cleans it up.
Improved futures
The code snippet gives you an idea how the future of std::future will look like.
1 2 3 4 5 6 7 8 9 10 |
future<int> f1= async([]() {return 123;}); future<string> f2 = f1.then([](future<int> f){ return f.get().to_string(); }); future<int> futures[] = {async([]() { return intResult(125); }), async([]() { return intResult(456); })}; future<vector<future<int>>> any_f = when_any(begin(futures), end(futures)); future<int> futures[] = {async([]() { return intResult(125); }), async([]() { return intResult(456); })}; future<vector<future<int>>> all_f = when_all(begin(futures), end(futures)); |
f1.then in line 2 returns a new future that will be executed if f1 is done with its work. any_f (line 6) will be performed if one of the futures in lines 4 and 5 is done. all_f will be performed if all of the futures in lines 8 and 9 are done.
One question is still not answered in my post. What have futures with functional programming in common? A lot! The improved futures are a monad. Suppose you don’t believe me. Watch: I see a Monad in your Future (Bartosz Milewski).
What’s next?
Now, it’s time to start with my systematic. In the next post, I will answer the question: What is functional programming?
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Seminars
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- C++20
Contact Me
- Mobil: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!