Better_Software_Header_Mobile Better_Software_Header_Web

Find what you need - explore our website and developer resources

The Practical Programmer’s Guide to C++20

C++20 provides C++ with even more power and expressiveness

#include <concepts>
#include <iostream>

std::integral auto factorial(std::integral auto a){ 
    if (a <= 0) return static_cast<decltype(a)>(1);
    else return a * factorial(a - 1); 
}
int main() {
    std::cout << factorial(10) << std::endl;
    return 0; 
}
main.cpp: In instantiation of ‘auto [requires ::Integral<<placeholder>, >] factorial(auto:11) [with auto:11 = double]:
main.cpp:50:33: required from here
main.cpp:27:30: error: use of function ‘auto [requires ::Integral<<placeholder>, >] factorial(auto:11) [with auto:11 = double]’with unsatisfied constraints
   27 | else return a * factorial(a - 1);
      | main.cpp:25:15: note:
   25 | Integral auto |
main.cpp:25:15: note:
main.cpp: In function ‘int main():
main.cpp:50:33: error: use of function ‘auto [requires ::Integral<<placeholder>, >] factorial(auto:11) [with auto:11 = double]’ with unsatisfied constraints
   50 | std::cout << factorial(-10.5) << std::endl; |^
main.cpp:25:15: note: declared here
   25 | Integral auto factorial(Integral auto a){
      | ^~~~~~~~~
main.cpp:25:15: note: constraints not satisfied
main.cpp: In instantiation of ‘auto [requires ::Integral<<placeholder>, >] factorial(auto:11) [with auto:11 = double]:
main.cpp:50:33: required from here
main.cpp:8:9: required for the satisfaction of ‘Integral<auto:11>[with auto:11 = double]
main.cpp:9:26: note: the expression ‘std::is_integral<_Tp>::value [with _Tp = double]’ evaluated to ‘false   9 | std::is_integral<T>::value;
     | ^~~~~
#include <iostream>
#include <complex>
#include <concepts>
using namespace std::complex_literals;

// while waiting for P2078 to add the is_complex type trait,
// we implement a makeshift version... template<typename T>
concept Complex = requires(T a, T b) {
        { a.imag() };
        { a.real() };
        { a + b } -> std::convertible_to<T>;
};

template<typename T>
concept Continuous = Complex<T> || std::floating_point<T>;

std::integral auto factorial(std::integral auto a) { 
    if (a <= 0) return static_cast<decltype(a)>(1);
    else return a * factorial(a - 1); 
}

std::floating_point auto factorial(std::floating_point auto a) { 
    decltype(a) one = 1.0;
    return std::tgamma(a + one); 
}

Complex auto complexGamma(Complex auto a){
    auto z = 0.0 + 0i;
    // A whole mess of complex math here...
    // (for one example, see https://www.johndcook.com/blog/cpp_gamma/)
    return z; 
}

Complex auto factorial(Complex auto a){ 
    decltype(a) one = 1.0;
    return complexGamma(a + one); 
}

int main() {
    using namespace std::complex_literals; 
    std::cout << factorial(10) << std::endl; 
    std::cout << factorial(-10.5) << std::endl;
    std::cout << factorial(10.0 + 2i) << std::endl; 
    return 0;
}
using namespace std::complex_literals;

// Definition #1 – handles floating types only
void f(std::floating_point auto x);

// Definition #2 – handles floats and complex numbers
void f(Continuous auto x);

int main() { 
    f(3.14f); // Case A: compiler calls f #1
    f(0.7070.707i); // Case B: compiler calls f #2
    return 0; 
}
#include <ranges>
#include <iostream>

int main()
{
    auto ints = std::ranges::iota_view{1, 33}; // Half-closed range, 32 is last
    auto even_bytes = [](int i) { return (i % 8)==0; }; // Keep only the byte boundaries
    auto largest_value = [](int i) { return (1ULL<<i)-1; }; // Biggest expressible unsigned
    for (uint64_t i : ints |
                           std::views::filter(even_bytes) |
                           std::views::transform(largest_value)) {
        std::cout << i << ‘ ‘;
    }
    std::cout << std::endl;
}
255 65535 16777215 4294967295
#include <iostream>
#include <vector>

#include <range/v3/view.hpp>
#include <range/v3/action.hpp>
#include <range/v3/view/istream.hpp>
#include <range/v3/range/conversion.hpp>

using namespace ranges;

auto string_to_lower(const std::string &s) { 
    return s | views::transform(tolower) | to<std::string>;
}

auto string_only_alnum(const std::string &s) {
    return s | views::filter(isalnum) | to<std::string>; 
}

bool string_is_empty(const std::string &s) {
    return s.empty(); 
}

int main(int argc, char *argv[])
{
    const int n = argc <= 1
                    ? 10
                    : atoi(argv[1]);

    const auto words = istream_range<std::string>(std::cin)
                                     | views::transform(string_to_lower)
                                     | views::transform(string_only_alnum)
                                     | views::remove_if(string_is_empty)
                                     | to_vector | actions::sort;
    const auto frequency = words
                                     | views::group_by(std::equal_to{})
                                     | views::transform([] (const auto &group) {
                                        const auto size = distance(group);
                                        const std::string word = *cbegin(group);
                                        return std::pair{size, word}; 
                                    })
                                      | to_vector | actions::sort;
    for (auto [count, word]: frequency | views::reverse | views::take(n)
                                    ) {
                        std::cout << count << “ “ << word << ‘\n’;
    }
    return 0;
}
// Note: the standard library isn’t yet module-ready in C++20,
// so this example won’t compile. If it was, it might look like this:

import std;

int main()
{
    std::cout << “Hello module world!\n”;
}
// simplelib.cpp

export module simple.example; // dots can be optionally inserted for module name readability

export void foo(){}        // foo() is accessible by outside world
void bar(){}                   // bar() is only visible within this file
generator<int> iota(int n = 0) {
    while(true)
        co_yield n++;
}
task<> tcp_echo_server() {
    char data[1024];
    for (;;) {
        std::size_t n = co_await socket.async_read_some(buffer(data));
        co_await async_write(socket, buffer(data, n));
    }
}
std::cout << std::format({1}, {0}!\n”, “world”, “hello”);
std::cout << std::format(“he{0}{0}o, {1}!\n”, “l”, “world”);
#include <compare>
#include <iostream>

class ExValue {
public:
    constexpr explicit ExValue(int val): value{val} { }
    auto operator<=>(const ExValue& rhs) const = default;
    constexpr auto operator<=>(const int& rhs) const {
        return value - rhs;
    }
private:
    int value;
};

template<typename A, typename B>
const auto whatis(A a, B b) {
    auto comparison = (a <=> b);
    if (comparison < 0)
        return “less”;
    else if (comparison > 0)
        return “greater”;
    else
        return “equals”;
}

int main() {
    std::cout << whatis(ExValue(10), ExValue(12)) << std::endl;
    std::cout << whatis(ExValue(12), ExValue(10)) << std::endl;
    std::cout << whatis(ExValue(8), ExValue(8)) << std::endl;
    std::cout << whatis(10, ExValue(12)) << std::endl;
    std::cout << whatis(100, ExValue(50)) << std::endl;
    std::cout << whatis(ExValue(10), 40) << std::endl;
    std::cout << whatis(ExValue(40), 10) << std::endl;

    std::cout << (bool) (ExValue(10) < ExValue(15)) << std::endl;
    std::cout << (bool) (ExValue(10) > ExValue(15)) << std::endl;
    std::cout << (bool) (ExValue(10) <= ExValue(15)) << std::endl;
    std::cout << (bool) (ExValue(10) >= ExValue(15)) << std::endl;
    std::cout << (bool) (ExValue(10) == ExValue(15)) << std::endl;
    std::cout << (bool) (ExValue(10) != ExValue(15)) << std::endl;
}

Tags:

c++