Walletfox.com

Fully Functional C++ with Range-v3

2nd edition, February 2021

Godbolt recommended

In case you are experiencing issues loading range-v3 in Wandbox, you can use Godbolt with this setting.

This page lists the most important changes that were made in the second edition of the book Fully Functional C++ with Range-v3.

Fizz Buzz

Algorithmic changes

Digits in a factorial

std::ceil was replaced by std::floor + 1. In this way, the algorithm works also for edge cases of 0 and 1. (p.24/4)

Approximation of e

To demonstrate the workings of views::partial_sum, the original Maclaurin expansion has been replaced by an adjusted factorial expansion, namely:


e ~ 1/1! + 2/2! + 3/3! + 4/4!...


This allows us to use views::iota, views::partial_sum and views::zip_with. (p.24)

Luhn algorithm

A note was added about how to deal with credit cards with an odd number of digits. Prepend 0 for this scenario using e.g. views::concat(views::single(0),...). (p.27)

Palindrome

Only half of the original range and half of the reversed range are now used for the final comparison, as this is a sufficient condition to determine palindromic behavior. (p.30)

Area of a polygon

A note was added on the assumptions of the solution, namely a non-intersecting polygon with a clockwise vertex order. (p.31)

Range comprehensions - Pythagorean triples

Euclid's solution which uses the generators m and n was improved to account for opposite parity (m odd, n even or vice versa) and coprimality, i.e. the greatest common divisors of m and n is 1. This approach allows to exclude the multiples of primitive solutions, such as [6,8,10]. (p.45)

Range-v3 comprehensions - Squarions

The check i != j highlighted below was removed as the same can be achieved by modifying the upper bound from views::iota(1,i+1) to views::iota(1,i). (p.46)

auto rng = views::for_each (views::iota(1), [](int i) {
        return views::for_each (views::iota(1,i+1), [i](int j) {
            return yield_if(i != j && ...);
        });
    });

Practice - chunk consecutive elements

Keys now represent positions of elements (not values). As a result, views::zip(v, views::iota(0)) has been replaced by v | views::enumerate. Note that we now explicitly require an unsigned type for the input vector. (p.53)

Range-v3-related changes

Seven bridges of Konigsberg and Matrix operations

views::all was removed from the example of Seven bridges of Konigsberg and Matrix operations, as this was only used to resolve a temporary issue related to arrays and Concepts. (p.32/2,37)

int const m [3][3] = {{1,2,3},{4,5,6},{7,8,9}};
// auto r =  m | views::all | views::join; // [1,2,3,4,5,6,7,8,9] 
auto r =  m | views::join; // [1,2,3,4,5,6,7,8,9] 

Quick reference

views::common and views::ref were added to the Quick reference. (p.68/X1,X2)

C++-related changes

Undefined behavior

Undefined behavior was discovered in the usage of yield_if in the examples of Molecular weight and Planetary masses. The issue was related to std::optional that would have been dereferenced regardless of whether it contained a value or not. While the original code compiled fine under CLANG, this was a case of undefined behavior. (p.41/6,43/7)

return yield_if(w.has_value(),*w); // undefined behavior
return yield_if(w.has_value(), w.value_or(0.0)); // ok
return yield_if(p_op.has_value(),  
                *p_op); // undefined behavior
return yield_if(p_op.has_value(),  
                p_op.value_or(Planet{})); // ok

unsigned char and cctype

char was changed to unsigned char in cases where std::isdigit, std::isalnum, std::tolower and std::isspace was used as part of a lambda expression (p.19,29,30,35,42,66). E.g.

return s | views::remove_if([](char c){
                              return std::isspace(c);}) // incorrect
return s | views::remove_if([](unsigned char c){
                              return std::isspace(c);}) // ok

Other changes

std::stringstream was globally replaced by std::istringstream.
The keyword static was added to the example Chunk consecutive vowels in the Practice section (p.52).
Digits in regular expressions were unified under [0-9] instead of \\d. (p.40)
An explicit conversion to int was added to determine whether a square root is an integer number in Range comprehensions - Squarions. (p.46)

Acknowledgement

A special thank you goes to Szilárd Szalóki for his comments on the 2nd edition.

Tagged: Range-v3