vtables under the surface | Episode 1 - Concepts

If you’ve been around C++ for a while, you’ve likely come across the terms “vtable”, “virtual table” or “virtual method table”. Vtables are not part of the C++ standard, even though this concept pops up almost immediately when you try to understand how virtual functions actually work in C++. Indeed, vtables are the most common implementation of polymorphism in C++.

You may also have already encountered a cryptic compilation error like “undefined reference to vtable for MyClass”. This may have left you perplexed because you didn’t explicitly create anything named “vtable” in your code. This error signals that, under the hood, the compiler generates vtables to handle virtual functions. If you’re curious about this error, here is a good discussion on Stack Overflow (the second answer is particularly enlightening).

Just in case: Debian Bookworm comes with a buggy GCC

Last month, I embarked on a new project. I set up a new computer with the latest Debian version, installed my favorite tools, and was all set to code. My first task was to migrate all the repositories from C++14 to C++20. While it might seem as straightforward as updating all the CMakeLists.txt to replace set (CMAKE_CXX_STANDARD 14) with set (CMAKE_CXX_STANDARD 20), reality proved otherwise (and I knew it would).

CPM.cmake to make CMake’s FetchContent easier

Scrolling through my list of starred projects on GitHub, I saw a tool I had forgotten, CPM.cmake, and decided that it was time to try it!

CPM.cmake (or just CPM) describes itself as “a cross-platform CMake script that adds dependency management capabilities to CMake”. It’s in fact a wrapper around CMake’s FetchContent module that makes it much easier to download packages.

To demonstrate its usage, I will build a project that depends on 3 libraries from GitHub: the famous Catch2 and fmt, and the probably not-as-famous-as-it-deserves scnlib.

The SYSTEM property from CMake 3.25

CMake 3.25 introduced a new property called SYSTEM. It will help us handle warnings from 3rd party libraries. Let’s see how!

The issue (with a minimal example project)

Here is a minimal example project to reproduce the issue. It simply prints something with the great fmt library:

#include <fmt/core.h>

int main()
{
    fmt::print("The answer is {}", 42);
}

The library is fetched from GitHub thanks to CMake’s FetchContent module:

cmake_minimum_required(VERSION 3.25)
project(CMake_SYSTEM)

# Set C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Fetch fmt from GitHub
include(FetchContent)

FetchContent_Declare(
        fmt
        GIT_REPOSITORY https://github.com/fmtlib/fmt.git
        GIT_TAG 9.1.0
)

FetchContent_MakeAvailable(fmt)

# Create executable
add_executable(${PROJECT_NAME} main.cpp)

target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic -Wswitch-enum)

target_link_libraries(${PROJECT_NAME} PRIVATE fmt)

The project can be built with:

Let’s try C++20 | Erase elements in a container with std::erase()

Imagine you have a vector of integers and you want to remove all zeros. It sounds like a simple task, right? Well, before C++20, it wasn’t that obvious. Let’s see how C++20 makes things easier.

Before

Since the beginning of C++, there is a free function named std::remove(). Young padawans may naively use it like this:

#include <iostream>
#include <vector>

int main() {
    std::vector data{12, 0, 654, 0, 4587, 0, 42};
    for (const auto& e: data) {
        std::cout << e << '\t';
    }

    std::cout << '\n';
    std::remove(data.begin(), data.end(), 0);

    for (const auto& e: data) {
        std::cout << e << '\t';
    }
}

They would get this weird result: