March 2024

C++20 Concepts Applied – Safe Bitmasks Using Scoped Enums -- Andreas Fertig

logo.pngIt can be hard to follow code using enable_if. Andreas Fertig gives a practical example where C++20’s concepts can be used instead.

C++20 Concepts Applied – Safe Bitmasks Using Scoped Enums

by Andreas Fertig

From the article:

The idea is that the bit-operators are often used with enums to create bitmasks. Filesystem permissions are one example. Essentially you want to be able to write type-safe code like this:

using Filesystem::Permission;
Permission readAndWrite{
  Permission::Read | Permission::Write};

The enum Permission is a class enum, making the code type-safe. Now, all of you who once have dealt with class enums know that they come without support for operators. Which also is their strength. You can define the desired operator or operators for each enum. The issue here is that most of the code is the same. Cast the enum to the underlying type, apply the binary operation, and cast the result back to the enum type. Nothing terribly hard, but it is so annoying to repeatedly type it.

Anthony solved this by providing an operator, a function template that only gets enabled if you opt-in for a desired enum. Listing 1 is the implementation, including the definition of Permission.

Aggregates: C++17 vs. C++20 -- Andreas Fertig

me.pngSometimes the small changes between two C++ standards really bite you. Today's post is about when I got bitten by a change to aggregates in C++20.

Aggregates: C++17 vs. C++20

by Andreas Fertig

From the article:

A harmless example

Attendees of my training classes usually assume that I know everything. I can say sorry, but that's not the case. One day in the past, I showed the following example during a class:

struct Point {
  int x;
  int y;
};

Point pt{2, 3};

The class did cover C++17 and C++20. The code of Point is a reduced version for this post. We were talking about C++17's structured bindings. I use Point to show the decomposition using C++ Insights.

I showed the behavior and certain variations while answering questions from the attendees. One question was about move and copy. The question leads me changing the initial code to the following one:

struct Point {
  int x;
  int y;

  Point(Point&&) = delete;  A
};

Point pt{2, 3};

As you can see, in A, I deleted the move constructor. As far as I remember, this topic was more or less the last one for this day. Everything went well and as expected.

Works on my machine

The next morning one of the attendees approached me with the question of why the code didn't compile on his machine. My usual answer here is that if C++ were be easy, I wouldn't have the job I have. Somehow this never shuts down such questions. I like curious attendees.

He shared his code via Compiler Explorer. Guess what? His code looked exactly like mine but didn't compile. Here is the error message from the compiler...

Data Structures and Algorithms with the C++ STL -- John Farrier

Explore the C++ STL with practical guidance on vectors, algorithms, and custom types for intermediate developers, enriched by real-world examples.

Data Structures and Algorithms with the C++ STL: A guide for modern C++ practitioners

by John Farrier

From the book:

While the Standard Template Library (STL) offers a rich set of tools for data structures and algorithms, navigating its intricacies can be daunting for intermediate C++ developers without expert guidance. This book offers a thorough exploration of the STL’s components, covering fundamental data structures, advanced algorithms, and concurrency features.

Starting with an in-depth analysis of the std::vector, this book highlights its pivotal role in the STL, progressing toward building your proficiency in utilizing vectors, managing memory, and leveraging iterators. The book then advances to STL’s data structures, including sequence containers, associative containers, and unordered containers, simplifying the concepts of container adaptors and views to enhance your knowledge of modern STL programming. Shifting the focus to STL algorithms, you’ll get to grips with sorting, searching, and transformations and develop the skills to implement and modify algorithms with best practices. Advanced sections cover extending the STL with custom types and algorithms, as well as concurrency features, exception safety, and parallel algorithms.

Workshops at using std::cpp 2024 in Madrid

Co-located with the C++ conference in Spain using std::cpp 2024 three one day trainings are offered on senders/receivers (Mateusz Pusz), concepts, ranges and views (Nicolai Josuttis) and design for safer C++ (Peter Sommerlad).

Workshops at using std::cpp 2024 in Madrid

by std:cpp

More detailed information:

Structured Concurrency with Senders and Receivers - Mateusz Pusz (April 22 from 9:00 to 18:30)
More info and registrations: https://www.fundacion.uc3m.es/formacion/structured-concurrency-with-senders-and-receivers/

Contemporary Design for Safer C++ - Peter Sommerlad (April 23 from 9:00 to 18:30)
More info and registrations: https://www.fundacion.uc3m.es/formacion/contemporary-design-for-safer-c/

Concepts, Ranges, and Views - The New Way of Programming in C++ - NIcolai Josuttis (April 24 from 9:00 to 18.30)
More info and registrations: https://www.fundacion.uc3m.es/formacion/concepts-ranges-and-views-in-c/

Come to Madrid and meet the experts!

 

 

Using std::expected from C++23 -- Bartlomiej Filipek

c++stories-usingstd.pngIn this article, we’ll go through a new vocabulary type introduced in C++23. std::expected is a type specifically designed to return results from a function, along with the extra error information.

Using std::expected from C++23

by Bartlomiej Filipek

From the article:

Imagine you’re expecting a certain result from a function, but oops… things don’t always go as planned:
/*RESULT*/ findRecord(Database& db, int recordId) {
    if (!db.connected())
        return /*??*/
   
    auto record = db.query(recordId);
    if (record.valid) {
        return record;
	
    return /*??*/
}
What can you do? What should you return or output through /*RESULT*/ ?

C++23: Bitwise Operations -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGWhile C++ is getting increasingly expressive with each new standard, we must not forget its origins. It is inherently a low-level language which operates close to the hardware level and allows operations that languages such as Javascript cannot even express.

A part of providing low-level functionalities is to be able to work on a byte or even on a bit level. In this post, we are going to see what related features C++23 brings or modifies.

C++23: Bitwise Operations

by Sandor Dargo

From the article:

constexpr std::bitset

To be fair, we already covered this earlier last year in C++23: Even more constexpr. But as I’m using this feature to demonstrate the next one, I decided to mention it again.

P2417R2 extends the constexpr interface of std::bitset. So far, only one of the constructors and operator[] was marked as constexpr. However, since std::string can be constexpr, all the internals - and therefore the full API - of std::bitset can be constexpr.

If you’re unfamiliar with std::bitset, it represents the object you pass in as a sequence of bits. You have to pass the number of bits as a non-type template argument.

#include <bitset>
#include <iostream>

int main()
{
    constexpr short i = 15;
    constexpr int numberOfBitsInInt = sizeof(i) * 8;
    std::cout << "i:" << i << ", i as binary: " << std::bitset<numberOfBitsInInt>(i) << '\n';
}
/*
i:15, i as binary: 0000000000001111
*/

It’s more capable than that, it also offers several ways to query the individual bits or set them.

C++23 likes to move it! -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGC++23 is going to bring us a few changes regarding move operations. It mostly means extended support in the standard library, but there is also one change directly in the language. Let’s start with that.

C++23 likes to move it!

by Sandor Dargo

From the article:

P2266R3 is a quite great proposal both in terms of its high-quality explanation and the amount of proposed changes in wording. I think if you’re interested in exploring a readable proposal, this might be the one.

Let me try to summarize it briefly.

Since the introduction of move semantics and rvalue references in C++11, we can return move-only types by value:

struct Widget {
    Widget(Widget&&);
};

Widget one(Widget w) {
    return w;
}
C++14 extended this support so that even converting constructors accepting an rvalue type can be called to invoke an implicit move.
struct RRefTaker {
    RRefTaker(Widget&&); // here is the converting constructor
};

RRefTaker two(Widget w) {
    return w;
}

As you can see, the two examples...