Functional in C++17 and C++20

Contents[Show]

Which functional feature can we expect with C++17, for which functional feature can we hope for with C++20? This is exactly 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 totally new concepts in C++.

timeline.FunktionalInCpp17Cpp20Eng

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 line 5 and 6. The parameter pack (...) is unpacked on the binary operator (... && args). The three dots define (ellipse) the parameter pack.

For the output of the program, I use the online compiler on cppreference.com.

foldExpressions

Haskell has the maybe monad, C++17 will get std::optional.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Stay informed about my mentoring programs.

 

 

Subscribe via E-Mail.

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 specially 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. The function getFirst will return the first element (line 8) if it exists. If not, a std::optional<int> object. I use in the main function two vectors. The calls getFirst in line 17 and 27 return a std::optional object. The object has in the case of myInt (line 19) a value; in the case myEmptyInt (line 29) no value. Now, I can display the value of myInt (line 20 - 22). The method value_or in line 22 and 30 will return a value if std::optional-object has a value if not a default value.

optinal

The impact of functional programming in C++ - in particular in the form of Haskell - increases significantly with C++20. Of course, it's a little big risky to make a prediction about C++20. I made once a mistake and said, that the following features are part of C++17. Which is if course not true.

C++20

Promised, the details to 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 certain 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 is template argument must 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 algorithms of the Standard Template Library directly on the whole container. But under the hood, we get totally 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 result the square of all odd number that is 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), remove 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. The input stream will be stopped by odds.

There is the 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 line 4 and 5 is done. all_f will be performed if all of the futures in line 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. If 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, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, 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, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Dominik Vošček, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

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++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall


Comments   

0 #1 Julian Calderon 2018-10-30 10:44
My question is for static_for or similar and more facilities for std::tuple. Does some of them come in C++20?
Quote

Mentoring

Stay Informed about my Mentoring

 

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 1624

Yesterday 4791

Week 1624

Month 191700

All 11672854

Currently are 232 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments