Blog

using std::cpp 2025 registration is open

using std::cpp 2025, the C++ conference in Spain, is now open for registration. The conference happens from March 19 to 21, 2025.

using std::cpp 2025 website

From the website:

Keynote speakers: Daniela Engert, Klaus Iglberger, Daniela Engert, Mateusz Pusz and Bjarne Stroustrup.

More details by visiting the full program.

Static Reflection in C++ -- Wu Yongwei

Depositphotos_226578348_S.jpgStatic reflection is under consideration for C++26. Wu Yongwei demonstrates how to achieve reflection now and shows some examples of what C++26 might make possible.

Static reflection will be an important part of C++ compile-time programming, as I discussed in the October issue of Overload [Wu24]. This time I will discuss static reflection in detail, including how to emulate it right now, before it’s been added to the standard.

Static Reflection in C++

by Wu Yongwei

From the article:

Background

Many programming languages support reflection (Python and Java, for example). C++ is lagging behind.

While this is the case, things are probably going to change in C++26. Also, what will be available in C++ will be very different from what is available in languages like Java or Python. The keyword is ‘static’.

Andrew Sutton defined ‘static reflection’ as follows [Sutton21]:

Static reflection is the integral ability for a metaprogram to observe its own code and, to a limited extent, generate new code at compile time.

‘Compile-time’ is the special sauce in C++, and it allows us to do things impossible in other languages:

  • Zero-overhead abstraction. As Bjarne Stroustrup famously put it, ‘What you don’t use, you don’t pay for. What you do use, you couldn’t hand-code any better.’ If you do not need static reflection, it will not make your program fatter or slower. But it will be at your hand when you do need it.
  • High performance. Due to the nature of compile-time reflection, it is possible to achieve unparalleled performance, when compared with languages like Java or Python.
  • Versatility at both compile time and run time. The information available at compile time can be used at run time, but not vice versa. C++ static reflection can do things that are possible in languages like Java, but there are things that C++ can do but are simply impossible in other languages.

What we want from reflection

When we talk about static reflection, what do we really want? We really want to see what a compiler can see, and we want to be able to use the relevant information in the code. The most prominent cases are enum and struct. We want to be able to iterate over all the enumerators, and know their names and values. We want to be able to iterate over all the data members of a struct, and know their names and types. Obviously, when a data member is an aggregate, we also want to be able to recurse into it during reflection. And so on.

Regretfully, we cannot do all these things today with ‘standard’ definitions. Yes, in some implementations it is possible to hack out some of the information with various tricks. I would prefer to use macros and template techniques to achieve the same purpose, as the code is somewhat neater, more portable, and more maintainable – at the cost of using non-standard definition syntaxes. Of course, nothing beats direct support from the future C++ standard.

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

Your attention is invited to the final 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. Why is it the chapter 12 of 11? We couldn't resist highlighting the favorite error of C and C++ programmers that even has its own name—the Off-by-one Error.

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

by Dmitry Sviridkin

From the article:

LLVM can generate the ud2 instruction on x86, which is an invalid instruction, often used as an indicator of unreachable code. If the program tries to execute it, it'll crash with the SIGILL signal. The code that causes undefined behavior can be marked as unreachable and replaced with ud2 or discarded in the future. In our wonderful example, the compiler is fully aware that buffer.size() == 0, and it hasn't been changed.

 

Learning to read C++ Compiler Errors: Failing to Create a shared_ptr -- Raymond Chen

Depositphotos_478507824_S.jpgThe trick to understanding C++ compiler error messages is to focus on two things. First, look at the beginning of the error message, which tells you what went wrong at a very low level. Then skip over the intermediate errors that follow the chain of calls until you end up at the line of code that you wrote. That original line of code is the one that is leading the compiler to a bad place. After that, you sometimes get supplemental information that helps you understand the low-level error better.

Learning to read C++ Compiler Errors: Failing to Create a shared_ptr

by Raymond Chen

From the article:

Consider the following erroneous code:

#include <memory>
#include <string>

struct WidgetOptions
{
    // imagine there is interesting stuff here
};

struct Widget
{
    Widget(WidgetOptions const* options);

    // imagine there is other interesting stuff here
};

void oops()
{
    WidgetOptions options;

    // The next line fails to compile
    std::shared_ptr<Widget> widget =
        std::make_shared<Widget>(options);
}

Here comes the error explosion.

// gcc
In file included from bits/stl_tempbuf.h:61,
                 from memory:66,
                 from sample.cpp:1:
bits/stl_construct.h: In instantiation of 'void std::_Construct(_Tp*, _Args&& ...) [with _Tp = Widget; _Args = {WidgetOptions&}]':
bits/alloc_traits.h:657:19:   required from 'static void std::allocator_traits<std::allocator<void> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = Widget; _Args = {WidgetOptions&}; allocator_type = std::allocator<void>]'
  657 |         { std::_Construct(__p, std::forward<_Args>(__args)...); }
      |           ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bits/shared_ptr_base.h:607:39:   required from 'std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {WidgetOptions&}; _Tp = Widget; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
  607 |           allocator_traits<_Alloc>::construct(__a, _M_ptr(),
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
  608 |               std::forward<_Args>(__args)...); // might throw
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
bits/shared_ptr_base.h:969:16:   required from 'std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = Widget; _Alloc = std::allocator<void>; _Args = {WidgetOptions&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
  969 |           auto __pi = ::new (__mem)
      |                       ^~~~~~~~~~~~~
  970 |             _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bits/shared_ptr_base.h:1713:14:   required from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {WidgetOptions&}; _Tp = Widget; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
 1713 |         : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...)
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bits/shared_ptr.h:463:59:   required from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {WidgetOptions&}; _Tp = Widget]'
  463 |         : __shared_ptr<_Tp>(__tag, std::forward<_Args>(__args)...)
      |                                                                  ^
bits/shared_ptr.h:1007:14:   required from 'std::shared_ptr<typename std::enable_if<(! std::is_array<_Tp>::value), _Tp>::type> std::make_shared(_Args&& ...) [with _Tp = Widget; _Args = {WidgetOptions&}; typename enable_if<(! is_array<_Tp>::value), _Tp>::type = Widget]'
 1007 |       return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a},
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1008 |                              std::forward<_Args>(__args)...);
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sample.cpp:22:33:   required from here
   22 |         std::make_shared<Widget>(options);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
bits/stl_construct.h:119:7: error: no matching function for call to 'Widget::Widget(WidgetOptions&)'
  119 |       ::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sample.cpp:11:5: note: candidate: 'Widget::Widget(const WidgetOptions*)'
   11 |     Widget(WidgetOptions const* options);
      |     ^~~~~~
sample.cpp:11:33: note:   no known conversion for argument 1 from 'WidgetOptions' to 'const WidgetOptions*'
   11 |     Widget(WidgetOptions const* options);
      |            ~~~~~~~~~~~~~~~~~~~~~^~~~~~~
sample.cpp:9:8: note: candidate: 'constexpr Widget::Widget(const Widget&)'
    9 | struct Widget
      |        ^~~~~~
sample.cpp:9:8: note:   no known conversion for argument 1 from 'WidgetOptions' to 'const Widget&'
sample.cpp:9:8: note: candidate: 'constexpr Widget::Widget(Widget&&)'
sample.cpp:9:8: note:   no known conversion for argument 1 from 'WidgetOptions' to 'Widget&&'
Compiler returned: 1
 

Pre-conference trainings at using std::cpp 2025 with Klaus Iglberger and Mateusz Pusz

Two one-day training workshops will be held in Madrid, co-located with the using std::cpp 2025 conference.

C++ Software Design - Klaus Iglberger

From the training description: This 1-day training explores modern C++ design and the modern forms of the classic Gang-of-Four (GoF) design patterns. It provides guidelines, idioms and best practices for sustainable and maintainable design, which enable programmers to create professional, high-quality code.

Concurrency Tools in the C++ Standard Library - Mateusz Pusz

From the training description: During this training, we will learn the concurrency utilities in the C++ Standard Library. We will also explain how new C++20 features improve the "old" abstractions we got before. We will talk about threads, mutexes,  deadlocks, work cancellation, semaphores, latches, barriers, and many more. We will also introduce a few higher-level abstractions (e.g., `concurrent_queue` and monitor design pattern).

 

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.