Starting a C++ project with CMake in 2024

A post on how I've recently started a new C++ project.

Starting a C++ project with CMake in 2024

by Jens Weller

From the article:

Last year I've written last year about my plans to return to C++, taking on some project ideas with C++20 and CMake.

The first project is now in its beginning, so I thought to share the steps so far. Some of this blog post is covered by my recent talk Starting a modern C++ project with CMake in 2024. In this post I'm going stay within the parts of the build tooling, following up with the code in other posts.

After working through the official CMake tutorial...

 

C++23: Allocator Related Changes -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGIn this post, we are going to review two changes related to allocators in C++. One is about providing size information about the allocated memory and the other is about how CTAD should happen for containers with non-default allocators.

C++23: Allocator Related Changes

by Sandor Dargo

From the article:

P0401R6 gives a new way to allocate memory on the heap to limit spurious reallocations.

The new interface of std::allocator looks like this, but there is also a free function version of it.

template<class Pointer>
  struct allocation_result {
    Pointer ptr;
    size_t count;
  };

// this class already exist:
namespace std {
  template<class T> class allocator {
   public:
   // lots of existing things
   // ...
   // this is the old way to allocate 
   [[nodiscard]] constexpr T* allocate(size_t n);

   // and this is the new way
   [[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n);

   // the interface for deallocation does not change
   constexpr void deallocate(T* p, size_t n);
  };
}
As you can see, allocate_at_least takes a number and it should allocate enough memory for at least that many instances of T on the heap. While allocate returns a single pointer to the beginning of the allocated memory, allocate_at_least returns a new struct called allocation_result which has two members, the “usual” pointer to the beginning of the allocated memory (ptr) and the number of Ts memory got allocated for (count). count must be at least as large as the input parameter n, but it can also be more.

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*/ ?