Articles & Books

Replace CRTP with Concepts -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGThis article explores how C++20 concepts can replace CRTP when implementing static interfaces for a family of classes. By leveraging concepts, we achieve cleaner, more readable, and less error-prone code—provided you have access to C++20.

Replace CRTP with Concepts

by Sandor Dargo

From the article:

In my Meeting C++ 2024 trip report, among my favourite ideas I mentioned Klaus Iglberger’s talk where he mentioned the possibility of replacing the curiously returning template pattern with the help of class tagging and concepts.

Class tagging might mean different things in different contexts, or at least might be implemented in different ways. The end goal is to mark, in other words, tag classes or functions to be used in certain contexts, with certain algorithms. As you’ll see, in our case it’ll also be a tool to prevent duck typing.

We are going to see an example implementation of a static interface with CRTP with a couple of different derived classes, then we’ll see the implementation without CRTP.

The CRTP solution

With the static interface, we are creating a static family of types. There is no need for dynamic polymorphism to share the same interface. It’s still granted through a base class, which is a template taking the deriving class as a parameter.

 

 

Solving the Puzzle of Trying to Put an Object into a std::optional -- Raymond Chen

RaymondChen_5in-150x150.jpgLast time, we investigated the puzzle of why the compiler wouldn’t let us put an object into a std::optional. It came down to the fact that the object is not copy-constructible, move-constructible, copy-assignable, or move-assignable, so there’s no way to put the temporary object into the std::optional.

Solving the Puzzle of Trying to Put an Object into a std::optional

by Raymond Chen

From the article:

What we have to do is construct the object in place inside the std::optional. And the C++ standard library term for “construct an object inside a container” is “emplace”.

struct Doodad
{
    Doodad();
    ~Doodad();
    std::unique_ptr<DoodadStuff> m_stuff;
};

struct Widget
{
    std::optional<Doodad> m_doodad;

    Widget()
    {
        if (doodads_enabled()) {
            m_doodad.emplace();
        }
    }
};

The parameters to emplace are whatever parameters you would have passed to the Doodad constructor. In our case, we wanted the default constructor, so that means that we pass nothing to emplace().

Court is in session: Top 10 most notorious C and C++ errors in 2024

Every year, we witness the same drama: bugs wreak havoc on our code as if asserting their dominance. But today, the tide turns—it's time for judgment. Let's dive into the most intriguing bugs we've uncovered this year.

Court is in session: Top 10 most notorious C and C++ errors in 2024

by Aleksandra Uvarova

From the article:

The seventh defendant, what are you draggin' behind your back? Show us quickly! Ah! A little thief! Decided to pocket a juicy chunk of code, huh? No chance, we're bringing this to the light. Honestly, we really wanted to paste the full code of the function here—which has almost 400 code lines—to make searching for errors more interesting. However, we don't want to abuse your mouse wheel, so we've included just the most intriguing part.

Write More C++ Code Thanks to constexpr -- Andreas Fertig

me.pngSince its introduction, constexpr in C++ has evolved significantly, offering powerful ways to optimize code at compile-time. This article shares a real-world story of using constexpr to dramatically reduce memory usage and code size in an embedded system, showcasing its potential to improve both performance and efficiency.

Write More C++ Code Thanks to constexpr

by Andreas Fertig

From the article:

I'm a big fan of constexpr and am not alone. Jason Turner is also very vocal, having coined the term "constexpr all the things".

Well, demonstrating the powers of constexpr is nonetheless something difficult. I know that from my training classes and various consulting contracts. Today, I'd like to share a story from back in time when a customer hired me to consult. They did develop an embedded system and ran out of memory. Not during run-time, but before. The features they wanted to put in the chip were too big in code size and somewhat RAM.

Initial constexpr-free example

They used a class I've seen a couple of times in embedded systems with some variations. A string brings its memory picky-back.

It’s just ‘,’ – The Comma Operator -- Coral Kashri

We all know that every ‘,’ matters in this language, so I decided to talk directly about that character today. So, how much impact can be for such a small little character?

It’s just ‘,’ – The Comma Operator

by Coral Kashri

From the article:

This operator comes from C, where it tells the compiler to evaluate all the expressions (left to right) and to return the result of the latest evaluated expression. For example:
     int a, b;
     a = 5, b = 4, b += a, ++a, std::cout << b << " " << a; // Prints 9 6

Another example of that operator usage is as follows:

     for (size_t i = 0, k = 500; i < 10; ++i, ++k) { /*...*/ }
 
We can see this operator in action in the third section of the for statement. It evaluates the ++i and then evaluates ++k.

How to Ensure a Class is not Copyable or Movable -- Sandor Dargo

Dargo-classisnotcopyable.pngThe topic of this post is to show different ways to ensure that a class is either non-moveable or non-copyable.

How to Ensure a Class is not Copyable or Movable

by Sandor Dargo

From the article:

If we follow the classification proposed by Sebastian Theophil, we can talk about 4 different class types:

  • value classes
  • container classes
  • resource classes
  • singleton classes

While the first two should be regular classes offering both copy and move semantics, the latter two are different. One shouldn’t be able to copy resources and singletons probably shouldn’t be moveable.

It’s up to us to ensure that a class we create implements the right special member functions (SMFs from now on). And the Hinnant table is here to guide us.

In C++, How Can I Make a Default Parameter be the This Pointer of the Caller? -- Raymond Chen

RaymondChen_5in-150x150.jpgIn C++, associating member objects like properties or events with their containing class often requires passing this redundantly. This article explores a generalized, flexible solution using templates, variadic arguments, and deducing this to streamline ownership initialization without boilerplate.

In C++, How Can I Make a Default Parameter be the This Pointer of the Caller? Revisited

by Raymond Chen

From the article:

Some time ago, we looked at making the default parameter of a method be the this pointer of the caller. The scenario was something like this:

struct Property
{
    Property(char const* name, int initial, Object* owner) :
        m_name(name), m_value(initial), m_owner(owner) {}

    ⟦ other methods elided - use your imagination ⟧

    char const* m_name;
    Object* m_owner;
    int m_value;
};

struct Widget : Object
{
    Property Height{ "Height", 10, this };
    Property Width{ "Width", 10, this };
};

and we didn’t want to have to type this as the last parameter to all the Property constructors. We came up with this:

template<typename D>
struct PropertyHelper
{
    Property Prop(char const* name, int initial)
    { return Property(name, initial, static_cast<D*>(this)); }
};

struct Widget : Object, PropertyHelper<Widget>
{
    Property Height = Prop("Height", 10);
    Property Width = Prop("Width", 10);
};

The Operations for Reading and Writing Single Elements for C++ Standard Library Maps -- Raymond Chen

RaymondChen_5in-150x150.jpgSome time ago, I noted that the std::map subscript operator is an attractive nuisance. It is the most convenient syntax, but is not often what you actually want.

The Operations for Reading and Writing Single Elements for C++ Standard Library Maps

by Raymond Chen

From the article:

I’ve broken down the various std::map lookup and update operations into a table so you can choose the best one for your situation.
2024-11-21_13-35-17.png

In the table above, key is the map key, value is the mapped type, and params are parameters to the mapped type constructor.

Note that insert and the first emplace¹ take a value which is discarded if it turns out that the key already exists. This is undesirable if creating the value is expensive.

One frustrating scenario is the case where the mapped type’s default constructor is not the constructor you want to use for operator[], or if you want the initial mapped value to be the result of a function call rather than a constructor. Here’s something I sort of threw together.

Trip Report: Fall ISO C++ Meeting in Wrocław, Poland -- Jonathan Müller

Depositphotos_170038592_S.jpgJonathan Müller attended the fall 2024 meeting of the ISO C++ standardization committee in Wrocław, Poland. This was the fifth meeting for the upcoming C++26 standard and the feature freeze for major C++26 features.

Trip Report: Fall ISO C++ Meeting in Wrocław, Poland

by Jonathan Müller

From the article:

For an overview of all the papers that made progress, read Herb Sutter's trip reportContracts and profiles are the big ticket items that made the most progress this meeting. Contracts is forwarded to wording review, while still being fiercely opposed by some. Profiles is essentially standardized static analysis to improve memory safety, although some deem it ineffective. Due to various scheduling conflicts I did not attend any of the relevant discussions in these spaces. Instead, I am going to share my thoughts about ranges, relocation, and reflection.

Ranges

I've spent the first day and a half co-chairing SG 9, the study group for std::ranges. During discussions, we realized two big holes in the range library that we need to address as soon as possible. They both concern the concept of sized ranges.

The first hole is related to proposal P3179—C++ parallel range algorithms, which adds an execution policy to the algorithms in std::ranges. This makes it trivial to run multi-threaded algorithms: Instead of writing std::ranges::transform(vec, output, fn), you write std::ranges::transform(std::execution::par, vec, output, fn) and now your input is split into multiple chunks and processed in parallel.

C++ programmer's guide to undefined behavior: part 11 of 11

Your attention is invited to the 11th part of an e-book on undefined behavior. This is not a textbook, as it's intended for those who are already familiar with C++ programming. It's a kind of C++ programmer's guide to undefined behavior and to its most secret and exotic corners. The book was written by Dmitry Sviridkin and edited by Andrey Karpov.

C++ programmer's guide to undefined behavior: part 11 of 11

by Dmitry Sviridkin

From the article:

Developing multithreaded applications is always challenging. The problem of synchronizing access to shared data is a perennial headache. It'd be ideal if we had a well-tested, reliable library of containers, high-level primitives, and parallel algorithms that managed all invariants. It'd be ideal if static compiler checks prevented us from misusing all these things. How nice it would be... Before C++11 and the standardized memory model, we could use threads but only at our risk. Starting with C++11, there are some pretty low-level primitives in the standard library. Since C++17, there are still various parallel versions of algorithms, but we can't even fine-tune the number of threads or their priorities.