Hello all,

Summary of San Diego C++ Meetup – Meeting session number 69. Took place on December 10 2024.

This is the last session for 2024!

Event link can be found here.

Topics we covered:

  • Modern C++ Programming: A tutorial/training session by Federico Busato.
  • ADL and the  std::swap idiom: Including a mention of  std::ranges::swap(). The discussion covered ADL, anonymous namespaces, and the global namespace, highlighting the subtleties when mixing them.
  • Mapping a runtime value to compile time: More details on this topic are provided below.
  • Variadic templates and fold expressions: Exploring techniques to eliminate duplicate code.
  • Lightning talk by GC: GC’s slide deck on “Stateless Allocators and Memory Resources” can be found here.

How can I map a runtime value to a compile-time value?

This was the main topic. The idea was as follows: given something like:

How can I take a runtime value n and pass it to the function? func<n> would not work since n is not a compile-time value!

The original problem to solve was the following (values are just for the example, it could be anything): for a range [0…5] map to 128, [6…10] map to 256, [11…max] map to 512.

People attending the session immediately suggested using an array/map/hash-map (aka unordered_map). I did not have any material to demonstrate anything with these elements, but before I show the solution presented in the session, let’s try to solve it first with the unordered_map type (since people claim it has O(1) efficiency).

This obviously cannot work. The compiler will complain: “call to non-‘constexpr’ function ’ … “. CE link.

So, what about trying to embed some constants in the “value” part of the unordered_map?

So the problem is, what do we place instead of the ????

What is the actual type? Even if I use integral_constant, which can be used in constant expression contexts, I don’t have a way to provide the type. std::integral_constant<std::size_t, 128> is different from std::integral_constant<std::size_t, 256>.

The next attempt was using Jason Turner’s idea of a “constexpr map.” For reference, here is Jason’s C++ Weekly:

Here is a link to CE trying to get it working. But again, this only works with compile-time inputs. The requirement was runtime inputs!

Let’s take a look at the actual implementation presented in the session. For this, you need to be familiar with:

  • std::lower_bound: Given the values [5, 10, max] and a needle, we need lower_bound to find the correct item among the values. Note that lower_bound is not a must here; we could also use a linear search like find/ find_if.
  • std::integral_constant<>: An important ingredient in the overall solution. This is where we can actually pass a constant to the template NTTP!
  • std::variant<> + std::visit() + overloaded{} idiom: For more information, check out cppreference and cppstories.com, which has tons of great articles on these.

Here is a CE link to the overall solution. Thanks to GC for suggesting constexpr on the return of lower_bound when working with C++20! My solution needed to compile with C++17.

Here is a simple explanation of what’s going on:

We have an array of variants. The std::variant is of type:

Think of it as mapping some number to std::integral_constant<size_t, some_value>.

Given a needle, find the index in the array of variants. We use:

  • lower_bound
  • overloaded{} idiom
  • std::visit to extract the first value in the pair<>

Once we have the result of lower_bound, given the iterator return value, we can compute the index using std::distance(base, iter).

Invoke a call that takes the index. We use the index with the array: arr[n].

Since arr[n] yield a variant type, we can run std::visit, getting the value and extracting the integral_constant, which is the second type in the pair.

Now, we can pass it to an NTTP by calling func<p.second()>(). The magic happens with integral_constant<>! It can be used as an NTTP!

That’s it for this session. I bet there are some other cool ways to achieve something similar!

Thank you for reading!

Kobi

Leave a Reply