Developer blog

  1. Home
  2. Career
  3. Developer blog
  4. Developer blog
if constexpr requires requires { requires }

Probably the two most useful features added to C++20 are `requires` and `requires`. They make it so much easier to control overload resolution, and when combined with `if constexpr` in C++17, they allow basic reflection-based optimizations in templates. While `requires requires` has gotten a lot of (negative?!) press for controlling overload resolution, its cousin `requires { requires }` is a bit overlooked.

Trip Report: Spring ISO C++ Meeting in Tokyo, Japan

Last week, I attended the spring 2024 meeting of the ISO C++ standardization committee in Tokyo, Japan. We made progress on a bunch of interesting features for C++26.

I'm the new assistant chair of SG 9, the study group for std::ranges!

In a week, the C++ standardization committee is meeting in Tokyo, Japan, to continue work on C++26. It will be my first meeting with an official role as assistant chair of SG 9.

Parsers vs Unicode

We think that keeping parser libraries Unicode-agnostic is the way to go.

Detecting multiple instantiations

How can a function know if it already has been instantiated before? Ideally this detection should happen during compilation. However, this is not possible in all cases. In this post we dive into stateful metaprogramming and throwing errors before main.

Enforcing that static local variables only exist once

C++ static local variables offer a good solution for some pertinent engineering problems. However, with code getting increasingly more generic, it’s too easy to end up with multiple instances of what should have been a singleton. To fix that, we came up with a zero-cost, compile-time check that a static local variable is instantiated at most once in the whole program.

C++ needs undefined behavior, but maybe less

The C++ standard does not specify all behavior. Some things are up to the implementation, while other operations are completely undefined, and the compiler is free to do whatever it wants. This is essential for some optimizations but can also be dangerous. The newly proposed erroneous behavior addresses it, but it cannot be used to eliminate all undefined behavior.

By Default Different

Sometimes, you need to register a name with your environment, like a named mutex to be shared across processes, a Win32 user-defined message or a file name for shared memory backing. And you must make sure that it does not clash with someone else's name - and that someone else could be you!

Compile-time sizes for range adaptors

For some ranges, like std::array<T, N>, the size is known at compile-time. Range adaptors like transform don't change the size of the underlying range, so they should conditionally provide the size at compile-time as well. How do we implement that without causing code duplication with the existing .size() member function that provides the size at runtime?

The new static constexpr std::integral_constant idiom

If your type provides a property with a compile-time known value (like the size of a std::array), consider using a static constexpr std::integral_constant member for it. This allows multiple convenient access syntaxes with only a single declaration.

Should we stop writing functions?

... and use named lambdas instead? This prevents ADL, gives you more control over overloading, and template parameters. The standard library has started using it in places, should we?

Event or no Event?

We have a cross-platform UI library with widgets. UI widgets by nature serve two masters: The code using them wants to style them and prepopulate their content. The user using them wants to interact with them and modify their content. Therefore, widgets typically offer functions to modify their properties, including the content, and also events that notify about content changes. For example, an edit box may offer a SetText function and a OnTextChange event. Here is the question: If SetText modifies the text, should the OnTextChange event fire?

Constrain your user-defined conversions

By default, user-defined conversion operators allow additional standard conversions afterwards. We can and should disable that by turning it into a constrained template.

Don‘t Make a Hash of it

Composing streaming hashes has its pitfalls. Treat it like serialization to avoid them.

Meaningful Exceptions

There are many APIs which on error throw exceptions. Or we write wrappers that turn error codes into exceptions. Is that a good idea?

An Actually Helpful Character Type

As we have seen last time, having char8_t is not terribly useful. But we discovered that another character type is actually quite useful.

char8_t Was a Bad Idea

We recently pondered whether to change all our chars to C++20 char8_t and decided against it, at least for now. At the face of it, adding char8_t seems straight-forward and appealing. There is already a char16_t and char32_t for UTF-16 and UTF-32 strings, so why not have a char8_t for UTF-8 strings?

Evil Reentrance

Everyone knows parallel programming is hard, and we talk about it a lot. We talk much less about which I think of as the little brother of parallel programming and also a popular source of bugs in complex systems: reentrance.

The Merits of optional<T const&>

Passing function parameters by const& is very common. Now, what do we do if such a parameter is optional? std::optional does not allow T to be a reference.

When Order Matters

Last time, I talked about inlining of single-call functions. In fact, there are situations where even for functions called multiple times, inlining functions into a larger one is beneficial.

Always Inline Single-Call Functions

Conventional coding rule wisdom says that functions can be too long and then must be broken into shorter ones. In this post we discover distinct disadvantages when it comes to reading and refactoring which we have not seen discussed elsewhere.

Poor Man's Exception

Let’s say we are performing a sequence of operations. Now, let’s assume each operation can fail, and returns false if it does. And if an operation fails, we want to abort and skip all subsequent operations. This post explores an alternative to if-cascades and exceptions to implement this.

The Value of Canonical Code

Often there are different ways of how to write a particular piece of code. It is a good idea to have agreement on which code to pick. At think-cell, we call this the canonical solution. In this post we discuss how to find it and why this is important.

Properties (2)

Meet the concept of hidden state: We define hidden state as state (information) that is represented and maintained in a data structure, but is not discernible by the user. Everybody who designs data structures frequently meets hidden state, whether they like it or not.

Properties (1)

Let's talk about a useful data structure for fonts. For the sake of this article, let's assume that a font consists of just a font face, a size and a flag for boldness. Turns out that even this simplified view of fonts is very useful in many use cases we encounter in our software.

tc::change

Welcome to this blog of our development work at think-cell. It will be mainly about programming in general and more specifically about C++. Our platforms are mainly Windows and macOS, with a bit of web development sprinkled in. We will write about anything that comes to our mind, architectural decisions, little nuggets of wisdom we found or rants about bugs in 3rd party software that leave us frustrated. I want to get started with a little utility that proved surprisingly useful for us and that has a bit more thinking behind it than is apparent at first sight.

We are hiring
  • Enough time to make sure that every detail of your solution is perfect
  • Become part of n international team of brilliant minds
  • No scheduled meetings