Storing compile-time values

This code is explained in detail in my talk slides “Crazy Generic Lambdas”

Modern C++ has brought us lambdas and constexpr if. This is good news for compile-time evaluation nerds like me. Now it is possible to seamlessly store key-value pairs within the closures of a lambda:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <type_traits>
#include <iostream>

consteval auto addItem(auto origin, auto key, auto value) 
    requires (std::is_same_v<void, decltype(origin(key))>) {
    
    auto result = [=](auto arg) constexpr
    {
        if constexpr(std::is_same_v<decltype(arg), decltype(key)>) {
            return value;
        } 
        else if constexpr(!std::is_same_v<void, decltype(origin(arg))>)
        {
            return origin(arg);    
        }
    };

    return result;
}

template<int I> struct index {};

int main()
{
    constexpr auto c = [](auto) {};
    constexpr auto c_ = addItem(c, index<1>{}, "Hello");
    constexpr auto c__ = addItem(c_, index<2>{}, 42);  
    
    // Will fail to compile as expected, since requires clause above kicks in
    // constexpr auto c___ = addItem(c__, index<2>{}, "WAT");  

    std::cout << c__(index<1>{}) << " ";
    std::cout << c__(index<2>{}) << "\n";   
    
    // Will fail to compile as expected, since return type is void 
    // std::cout << c__(index<3>{}) << "\n";   
}