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";
}