Bitfields and strongly-typed enums

Something is wrong with the following code, can you spot what it is? (If in doubt, try compiling it.)

enum class Color { red = 1, green = 2, blue =  4 };
auto yellow = Color::red | Color::green;

As you may have found out, the compiler complains with a message such as: error: no match for 'operator|' (operand types are 'Color' and 'Color'). The simplistic solution is to remove the class keyword, and use the “plain” enum type, where the enumerators are implicitly convertible to and from int.

Continue reading “Bitfields and strongly-typed enums”

String literals as switch/case labels

This article aims to show that switching on string values and matching them with string-valued case labels is both practical and possible in Modern C++ (since C++17), with a minimal amount of boilerplate code being necessary. The C++ switch statement is almost unchanged since the days of C, apart from the availability of the [[fallthrough]]; attribute to allow a non-empty case to fall through to the next, and the possibility of preceding the switch expression with an initializer. Importantly, case labels can still be only of integral type (from char up to long long).

The steps needed are as follows:

  1. Create a hashing function that generates an integral hash from a string (we’ll use C++17’s std::string_view as the source type)
  2. Make sure this function can be declared constexpr (again, this needs C++17)
  3. Write an operator"" function (again constexpr) which calls the hashing function
Continue reading “String literals as switch/case labels”

Writing assert() in C++

So we all know assert() from C’s Standard Library, right? If we implemented it ourselves as a macro, it might look something like this:

#define assert(x, msg) \
    if(!(x)) { fprintf(stderr, "Fatal error: %s\n", msg); abort(); }

With C++, any type that has operator! defined is compatible with this macro. We can then write:

std::ifstream infile("myfile.txt");
assert(infile, "could not open file");
Continue reading “Writing assert() in C++”

Python’s range() in 20 lines of C++

The Python language does not have an iteration-based for-loop in the style of C and C++; instead it uses a Python list (or tuple) in conjunction with the keywords for and in. Python 2 uses the helper function range() to create a suitable list, while Python 3 implements this function as an iterator class (to avoid a potential delay before the first iteration of the loop due to populating a very large list). If we were to implement this in C++, we could populate a std::vector and iterate over that, but this could potentially suffer from the space-and-time overheads of the Python 2 version. So instead we’ll choose to use iterators in the style of the STL containers (actually, if you know your Standard Library iterator categories, it’s forward iterators we want to emulate, however I haven’t used the actual iterator types available because of only wanting to be compatible with range-for, not the standard containers).

Continue reading “Python’s range() in 20 lines of C++”

printf() to a std::string

Just in case you weren’t already aware, a part of the upcoming C++20 Standard is a text formatting library (based upon the popular, free, third-party {fmt} library). It looks like being a great addition to the Standard Library, providing ease-of-use, performance and type-safety.

Before we put the <iomanip> and <cstdio> C++ headers into the museum however, lets look at something which is also possible in Modern C++, using a printf()-style format string to construct a std::string. The prototype of this function is therefore:

std::string string_printf(const char *fmt,...);
Continue reading “printf() to a std::string”

Numbers to English words

A classic course assignment is to write a program that prints out an arbitrarily-long decimal number in units, thousands, millions… and so on. This article looks at how to implement this efficiently in Modern C++, using head recursion. This is where the logic of a function is generalized so that it can usefully call itself a (finite) number of times. The more commonly found (and simpler to understand) form of recursion is tail recursion, where the result of the function (the return value) can be used to compute the final required value. In case you’re not up to speed on tail recursion, the classic example is a function which computes n! (that is, the factorial function from Mathematics).

Continue reading “Numbers to English words”

An Introductory Tutorial for Modern C++

This site contains an original, self-contained guide to learning the fundamentals of Modern C++, intended to be the basis of a self-study course. Some Chapters depend upon material presented in earlier ones, so studying them linearly is recommended. There are also regular posts (accessible from the front page) which cover topics or areas of C++ not covered in the course.

If you have any queries or suggestions, please leave a comment. The course materials are in a completed state (updated to cover parts of C++23) and are made freely available here as well as being hosted on GitHub:

  1. About this Tutorial
  2. String and Character Literals
  3. Variables, Scopes and Namespaces
  4. Conditions and Operators
  5. Functions
  6. Arrays, Pointers and Loops
  7. Enums and Structs
  8. Strings, Containers and Views
  9. Files and Formatting
  10. Classes, Friends and Polymorphism
  11. Templates, Exceptions, Lambdas, Smart Pointers

Last update: 2025/11/24 – update to Chapter 2, and usage guide in the notebooks download