TimelineCpp20Libraries

C++20: The Library

My last post “C++20: The Core Language” presented the new features of the C++20 core language. Today, I continue my journey with an overview of the C++20 library.

TimelineCpp20LibrariesThe image shows you my plan for today.

Library

Calendar and Time-Zone

The chrono library from C++11/14 was extended with a calendar and time-zone facility.  If you don’t know the Chrono library, read my posts to time.

Calendar

Calendar: consists of types, which represent a year, a month, a day of a weekday, and an n-th weekday of a month. These elementary types can be combined into complex types such for example year_month, year_month_day, year_month_day_last, years_month_weekday, and year_month_weekday_last. The operator “/” is overloaded for the convenient specification of time points. Additionally, we will get new with C++20 literals: d for a day and y for a year.

Time-Zone

Time points can be displayed in various specific time zones.

Due to the extended chrono library, the following use cases are easy to implement:

  • representing dates in various forms
auto d1 = 2019y/oct/28;
auto d2 = 28d/oct/2019;
auto d3 = oct/28/2019; 

 

  • get the last day of a month
  • get the number of days between two dates
  • printing the current time in various time-zones

If you want to play with these features, use Howard Hinnards implementation on GitHub. Howard Hinnard, the author of the calendar and time-zone proposal, also created a playground for it on Wandbox.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • Do you want to stay informed: Subscribe.

     

    #include "date.h"
    #include <iostream>
    
    int
    main()
    {
        using namespace date;
        using namespace std::chrono;
        auto now = system_clock::now();
        std::cout << "The current time is " << now << " UTC\n";
        auto current_year = year_month_day{floor<days>(now)}.year();
        std::cout << "The current year is " << current_year << '\n';
        auto h = floor<hours>(now) - sys_days{jan/1/current_year};
        std::cout << "It has been " << h << " since New Years!\n";
    }
    

     

    Of course, C++20 uses the std::chrono namespace instead of the date namespace. Here is the output of the program:

    calendar

     

    std::span

    A std::span is an object that can refer to a contiguous sequence of objects. A std::span, sometimes also called a view, is never an owner. This contiguous memory can be an array, a pointer with a size, or a std::vector. A typical implementation needs a pointer to its first element and a size. The main reason for having a std::span<T> is that a plain array will decay to a pointer if passed to a function; therefore, the size is lost. std::span<T> automatically deduces the size of the plain array or the std::vector. If you use a pointer to initialize a std::span<T>, you must provide the constructor’s size.

    template <typename T>
    void copy_n(const T* p, T* q, int n){}
    
    template <typename T>
    void copy(std::span<const T> src, std::span<T> des){}
    
    int main(){
        
      int arr1[] = {1, 2, 3};
      int arr2[] = {3, 4, 5};
      
      copy_n(arr1, arr2, 3);         // (1)
      copy(arr1, arr2);              // (2)
        
    }
    

     

    In contrast to the function copy_n (1), copy (2) doesn’t need the number of elements. Hence, a common cause of errors is gone with std::span<T>.

    constexpr Containers

    C++ becomes more and more constexpr. For example, many algorithms of the Standard Template Library get with C++20 a constexpr overload.  constexpr for a function or function template means that it could be performed at compile time. The question is now, which containers can be used at compile time? With C++20, the answer is std::string and std::vector.

    Before C++20, both could not be used in a constexpr evaluation because of three limiting aspects.

    1. Destructors couldn’t be constexpr.
    2. Dynamic memory allocation/deallocation wasn’t available.
    3. In-place construction using placement-new wasn’t available.

    These limiting aspects are now solved.

    Point 3 talks about placement-new, which is quite unknown. Placement-new is often used to instantiate an object in a pre-reserved memory area. Besides, you can overload placement-new globally or for your data types.

    char* memory = new char[sizeof(Account)];        // allocate memory
    Account* account = new(memory) Account;          // construct in-place
    account->~Account();                             // destruct
    delete [] memory;                                // free memory
    

     

    Here are the steps to use placement-new. The first line allocates memory for an Account, which is used in the second line to construct an account in place. Admittedly, the expression account->~Account() looks strange. This expression is one of these rare cases in which you must explicitly call the destructor. Finally, the last line frees the memory.

    I will not go further into the details of constexpr Containers. If you are curious, read proposal 784R1.

    std::format

    cppreference.com/concisely describes the new formatting library: “The text formatting library offers a safe and extensible alternative to the printf family of functions. It is intended to complement the existing C++ I/O streams library and reuse some of its infrastructure such as overloaded insertion operators for user-defined types.”. This concise description includes a straightforward example:

    std::string message = std::format("The answer is {}.", 42);
    

     

    Maybe, this reminds you of Pythons format string. You are right. There is already an implementation of the std::format on GitHub available: fmt. Here are a few examples from the mentioned implementation. Instead of std, it uses the namespace fmt.

    • Format and use positional arguments
    std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
    // s == "I'd rather be happy than right."
    

     

    •  Convert an integer to a string in a safe way
    fmt::memory_buffer buf;
    format_to(buf, "{}", 42);    // replaces itoa(42, buffer, 10)
    format_to(buf, "{:x}", 42);  // replaces itoa(42, buffer, 16)
    // access the string with to_string(buf) or buf.data()
    

     

    • Format user-defined types
    struct date {
      int year, month, day;
    };
    
    template <>
    struct fmt::formatter<date> {
      template <typename ParseContext>
      constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
    
      template <typename FormatContext>
      auto format(const date &d, FormatContext &ctx) {
        return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
      }
    };
    
    std::string s = fmt::format("The date is {}", date{2012, 12, 9});
    // s == "The date is 2012-12-9"
    

     

    What’s next?

     

    As promised, I will dive deeper into a future post in the library. But first, I have to finish my high-level overview of C++20. My next post is about the concurrency features.

     

     

    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, Matt Godbolt, and Honey Sukesan.

    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

    Modernes C++ GmbH

    Modernes C++ Mentoring (English)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *