layout: true --- class: middle template: inverse background-color: gray background-image: url(images/DSC_0253_small.jpg) background-size: cover .center[ # .white[Crazy Generic Lambdas] ## .white[A glimpse on template, auto and those ...] .white[Duration: 0:16:25 (#NoEstimates)] ![]() ] --- layout: false background-image: url(https://ducktrain.io/wp-content/uploads/2020/07/Ducktrain_BicycleLane2.png) background-size: cover # .fixed-pos-nearly-llc[Visit [https://ducktrain.io](https://ducktrain.io)] .center[
] --- layout: false ## This talk and its accompanying code is Open Source™ You can download this talk **and** code samples at
https://github.com/daixtrose/crazy-generic-lambdas .split-50[ .column[
- Code published under MIT licence - The code for the talk framework is based on [remark.js](https://github.com/gnab/remark) and is stolen from [Kirk Shoop's Intro to RxCpp](https://github.com/kirkshoop/introductionToRxcpp) - Please contribute fixes or [file an issue](https://github.com/daixtrose/crazy-generic-lambdas/issues) if you find errors or know about improvements. - Fotos published under [CC BY-SA](https://creativecommons.org/licenses/by-sa/4.0/legalcode) .image-fixed-40[] ] .column[  ] ] ??? In order to make it easy for you to follow this talk and for everyone who is visually impaired I share the code for this talk on my GitHub account. You can download the code and the utilities I present here under permissive licences. The talk and code are distributed under the MIT license. The fotos that I made and use as illustrations are available under the Creative Commons Attribution-ShareAlike. The code that I have stolen and reused here is also under MIT license. So everyone should be fine. --- background-image: url(images/DSC_0085_small.jpg) background-size: cover --- layout: false background-image: url(images/DSC_0145_small.jpg) background-size: cover # What are Lambdas? Lambdas are `syntactic sugar` for function **objects** .split-60[ .column[ ```c++ #include
struct C { int operator()() { return 42; } }; int main() { C c; // eagerly waiting for std::print std::cout << c() << "\n"; } ``` ] .column[
 ] ] --- layout: false background-image: url(images/DSC_0145_small.jpg) background-size: cover # What are Lambdas? Lambdas are syntactic sugar for function **objects** .split-60[ .column[ ```c++ #include
int main() { auto c = []() { return 42; }; // eagerly waiting for std::print std::cout << c() << "\n"; } ``` ] .column[
 ] ] --- layout: false background-image: url(images/DSC_0371_small.jpg) background-size: cover # Lambdas are Objects! > Check on https://cppinsights.io/ decompiler .split-30[ .column[ ```c++ `auto` c = []() { return 42; }; ``` ] .column[ ```c++ class `__lambda_1_11` { public: inline int operator()() const { return 42; } // ... some function pointer stuff omitted ... // __lambda_1_11() = default; }; `__lambda_1_11` c = __lambda_1_11{}; ``` ] ] --- layout: false background-image: url(images/DSC_0174_small.jpg) background-size: cover # Lambdas Can Store Objects via Binding .split-40[ .column[ ```c++ auto c = [](int i) { auto result = [`=`] { return `i`; }; return result; }; static_assert(42 == c(42)()); ``` ] .column[ ```c++ class __lambda_1_14 { public: inline `__lambda_2_23` operator()(int i) const { class __lambda_2_23 { private: int `i`; public: __lambda_2_23(int & _i) : i{_i} {} inline int operator()() const { return i; } }; __lambda_2_23 result = __lambda_2_23{i} return __lambda_2_23(result); } __lambda_1_14 c = __lambda_1_14{}; ``` ] ] --- background-image: url(images/DSC_0251_small.jpg) background-size: cover --- layout: false background-image: url(images/DSC_0064_small.jpg) background-size: cover # Lambdas and Constexpr > Lambdas can be marked as *can be evaluated at compile time* via `constexpr` .split-60[ .column[ ```c++ int main() { auto c = []() constexpr { return 42; }; static_assert(42 == c()); } ``` ] .column[ ] ] --- layout: false background-image: url(images/DSC_0064_small.jpg) background-size: cover # Lambdas and Constexpr > A lambda is implicitly constexpr if its result satisfies the requirements of a constexpr function: ```c++ int main() { /* implicitly constexpr */ auto c = []() /* implicitly constexpr */ { return 42; }; // Won't compile, no reassignment possible: // c = []() { return 43; }; static_assert(42 == c()); } ``` --- layout: false background-image: url(images/DSC_0065_small.jpg) background-size: cover # Lambdas and Consteval > Lambdas can be marked as *must evaluate at compile time* via `consteval`, but since > they are implicitly constexpr, consteval is not always necessary. ```c++ int main() { auto c = [](int i) consteval { return i + 1; }; static_assert(42 == c(41)); } ``` --- layout: false background-image: url(images/DSC_0467_small.jpg) background-size: cover # Generic Lambdas > Lambdas can be generic (as I promised) .split-50[ .column[ ```c++ #include
int main() { auto c = []`
`(T i) { static_assert( std::is_integral_v
); return i + 1; }; static_assert(42 == c(41)); } ``` ] .column[ ```c++ #include
int main() { auto c = [](`auto` i) { static_assert( std::is_integral_v< `decltype(i)`>); return i + 1; }; static_assert(42 == c(41)); } ``` ] ] --- layout: false background-image: url(images/DSC_0467_small.jpg) background-size: cover # Generic Lambdas: Explicit Parametrization ```c++ #include
int main() { auto c = []
(T i) { return i + 1; }; // error: // `'c' does not name a template but is followed by template arguments` // static_assert(42 == c`
`(41)); static_assert(42 == c.`template operator()
`(41)); } ``` --- layout: false background-image: url(images/DSC_0467_small.jpg) background-size: cover # Generic Lambdas: Explicit Parametrization for Value Parameters ```c++ #include
int main() { auto c = []<`int I`>() { return I + 1; }; static_assert(42 == c.template operator()<`41`>()); // ^^^^^^^^^^^^^^^^^^^^^^^ } ``` --- layout: false background-image: url(images/DSC_0467_small.jpg) background-size: cover # Generic Lambdas: Explicit Parametrization for Value Parameters ```c++ #include
// a helper function template
consteval auto `get`(auto const & c) { return c.`template operator()
`(); } int main() { auto c = []
() { return I + 1; }; static_assert(42 == `get<41>`(c)); } ``` --- background-image: url(images/DSC_0137_small.jpg) background-size: cover --- background-image: url(images/DSC_0229_small.jpg) background-size: cover # Store Multiple Values in a Lambda ```c++ template
consteval auto get(auto c) { return c.template operator()
(); } int main() { constexpr auto c = []
() {}; // start empty constexpr auto c_ = `addItem<1>`(c, "Hello"); // add an item constexpr auto c__ = `addItem<2>`(c_, 42); // add another one std::cout << `get<1>`(c__) << " "; // get the 1st value back std::cout << `get<2>`(c__) << "\n"; // get the 2nd value back } ``` --- background-image: url(images/DSC_0229_small.jpg) background-size: cover # .white[
addItem
] ```c++ template
consteval auto `addItem`(auto origin, auto value) { auto result = [=]
() constexpr { if constexpr(I == J) { return value; } else { return origin.template operator()
(); } }; return result; } ``` --- background-image: url(images/DSC_0070_small.jpg) background-size: cover --- ```c++ template
consteval auto `addItem`(auto origin, auto `value`) { // _return_ a lambda that _returns_ `value` ... auto result = [`=`]
() constexpr { // ... if (and only if) called with `I` if `constexpr`(`I` == J) { return value; } else { return origin.template operator()
(); } }; return result; } ``` --- ```c++ template
consteval auto addItem(auto `origin`, auto value) { auto result = [=]
() constexpr { if `constexpr`(I == J) { return value; } `else` { return `origin.template operator()
()`; } }; return result; } ``` --- # Store Multiple Values in a Lambda ```c++ constexpr auto `c` = `[]
() {}`; // start empty // | // \----------------| // V constexpr auto `c_` = addItem<1>(`c`, "Hello"); // add an item // | // \-----------------| // V constexpr auto `c__` = addItem<2>(`c_`, 42); // add another one std::cout << get<1>(c__) << " "; // get the 1st value back std::cout << get<2>(c__) << "\n"; // get the 2nd value back // std::cout << get<3>(c__) << "\n"; // compiler error (void) ``` --- # Hinder Overwrites ```c++ template
consteval auto get(auto c) { return c.template operator()
(); } int main() { constexpr auto c = []
() {}; // start empty constexpr auto c_ = addItem<1>(c, "Hello"); // add an item constexpr auto c__ = `addItem<1>(c_, "World")`; // <--- should fail! } ``` --- ```c++ template
consteval auto addItem(auto origin, auto value) requires (std::is_void_v
())>) { auto result = [=]
() constexpr { if constexpr(I == J) { return value; } else { return origin.template operator()
(); } }; return result; } ``` --- layout: false background-image: url(images/DSC_0198_small.jpg) background-size: cover --- layout: false # You can inherit from the type of a Lambda https://godbolt.org/z/5f168eofh ```c++ [[maybe_unused]] auto fi = [](int i) { return i * i; }; [[maybe_unused]] auto fd = [](double d) { return 2.0 * d; }; struct overload : `decltype(fi), decltype(fd)` { using decltype(fi)::operator(); using decltype(fd)::operator(); }; int main() { overload o; // We can ... o(42); // Country ... o(42.0); // and Western! } ``` --- layout: false # You can inherit from the type of a Lambda ```c++ auto fi = [](int i) { return i * i; }; auto fd = [](double d) { return 2.0 * d; }; template
struct overload : F1, F2 { using F1::operator(); using F2::operator(); }; auto make_overload(auto f1, auto f2) { return overload
{}; } int main() { auto o = make_overload(fi, fd); // We can ... o(42); // Country ... o(42.0); // and Western! } ``` --- layout: false # You can inherit from the type of a Lambda See https://arne-mertz.de/2018/05/overload-build-a-variant-visitor-on-the-fly/ ```c++ template
struct overload : Fs... { template
overload(Ts&& ...ts) : Fs{std::forward
(ts)}... {} using Fs::operator()...; }; template
overload(Ts&&...) -> overload
...>; ``` --- class: middle template: inverse background-image: url(images/Cappuchino_small.jpg) background-size: cover .center[ > # Thank You for Your Attention ] --- background-image: url(images/DSC_0253_small.jpg) background-size: cover