[{"content":"","date":null,"permalink":"https://dev0notes.com/tags/c++/","section":"Tags","summary":"","title":"C++"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/c++23/","section":"Tags","summary":"","title":"C++23"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/functional-programming/","section":"Tags","summary":"","title":"Functional Programming"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/lambdas/","section":"Tags","summary":"","title":"Lambdas"},{"content":"","date":null,"permalink":"https://dev0notes.com/posts/","section":"Posts","summary":"","title":"Posts"},{"content":"There are algorithms that have a natural recursive representation and are very cumbersome or painful to write iteratively. With the advent of lambda expressions in C++11, it seemed only natural that they should support recursive calls. But reality hit hard: recursion and lambdas didn\u0026rsquo;t mix at all until C++14, and even then the support was far from programmer-friendly. The newest C++ edition finally brings the possibility of creating a recursive lambda to the table.\nTake a look at the classical Fibonacci sequence implementation:\nlong fibonacci(int n) { return n \u0026lt; 2 ? n : fibonacci(n-1) + fibonacci(n-2); }That\u0026rsquo;s it\u0026mdash;a single line of code that contains two recursive calls is all you need.\nlong fibonacci(int n) { if (n \u0026lt; 2) return n; long a{0}, b{1}; while (--n) { auto temp = a + b; a = b; b = temp; } return b; }Long and ugly, and it doesn\u0026rsquo;t look like the Fibonacci sequence at all, right? The recursive version, on the other hand, is both compact and very readable. Lambda expressions, introduced in C++11, were advertised as a perfect solution for writing simple, short functions\u0026mdash;precisely the case of fibonacci in its recursive flavor. If that\u0026rsquo;s what you thought, you were in for a big disappointment. The obvious lambda solution:\nint main(){ auto fibonacci = [](int n) -\u0026gt; long { return n \u0026lt; 2 ? n : fibonacci(n-1) + fibonacci(n-2); }; std::cout \u0026lt;\u0026lt; fibonacci(10); // should print 55 }\u0026hellip; fails to compile, with a telling error that a lambda expression cannot be used before it\u0026rsquo;s fully defined. That is, you cannot refer to a lambda expression within it, because it\u0026rsquo;s still not fully known to the compiler. That\u0026rsquo;s both disappointing and seemingly silly because a function object equivalent compiles and works just fine:\nstruct fibonacci { long operator()(int n) const noexcept { return n \u0026lt; 2 ? n : operator()(n-1) + operator()(n-2); } }; int main(){ std::cout \u0026lt;\u0026lt; fibonacci{}(10); // should print 55 }And at their heart, lambdas are nothing more than sugar coating applied on top of function objects. As often happens, the explanation for this behavior is in the details. In the lambda solution, fibonacci is a variable that holds an object of the closure type generated by the compiler. Referring to this object within the lambda\u0026rsquo;s body is a big no-no, because this object is not yet fully defined. To sum it up, the recursive lambda solution doesn\u0026rsquo;t work and won\u0026rsquo;t work. At this moment you could stop and give up. But let\u0026rsquo;s be honest, lambdas are made for short single-use functions (like fibonacci) and, on top of that, they have a certain allure to them.\nMaking lambdas recursive with C++14 #A recursive function must be able to refer to itself. Here\u0026rsquo;s the problem: the only way for a lambda expression to know about other objects, including itself, is to either capture them or pass them as arguments. Capturing won\u0026rsquo;t help because you cannot capture something that doesn\u0026rsquo;t exist yet:\nauto fibonacci = [\u0026amp;fibonacci](int n) -\u0026gt; long { /* ... */}; // ERROR So this approach won\u0026rsquo;t cut it. To use the second one, the argument-passing approach, the parameter\u0026rsquo;s type needs to be known. Unfortunately, lambdas don\u0026rsquo;t come with type names known to the programmer, and the only solution seems to be decltype:\nauto fibonacci = [](const decltype(fibonacci)\u0026amp; self, int n) -\u0026gt; long { /*...*/ }; // ERROR But this cannot work! fibonacci\u0026rsquo;s type is not yet known when it\u0026rsquo;s used in the decltype specifier.\nAt moments like this, when the compiler doesn\u0026rsquo;t seem to appreciate just how badly you want to bend the type system to your needs, templates usually come to mind. Luckily, partial support for templates was added to lambdas in C++14. In this limited form, a lambda expression can have generic parameters specified with the placeholder auto. And so, fibonacci spiked with generics becomes:\nauto fibonacci = [](const auto\u0026amp; self, int n) -\u0026gt; long { return n \u0026lt; 2 ? n : self(self, n-1) + self(self, n-2); };Let\u0026rsquo;s zoom in on it. The generic fibonacci takes, as its first argument, self of some unknown, templated, auto type. Later, in the lambda\u0026rsquo;s body, self is used as a function and passed two arguments: self (again) and the integer n (less one or two). The call to self is what makes fibonacci recursive. To use it, you\u0026rsquo;ll need to pass the lambda expression to itself and let the compiler figure out the types:\nauto fibonacci = /* ... */ ; std::cout \u0026lt;\u0026lt; fibonacci(fibonacci, 10);And\u0026hellip; it just works. But there\u0026rsquo;s an elephant in the room\u0026hellip;\nMaking lambdas recursive with higher-order functions #Using fibonacci became unintuitive at best. There\u0026rsquo;s an explicit self argument that needs to be passed, making the function useless in most commonplace scenarios. As it often happens, the solution is adding another layer of indirection. By embedding the renamed fibonacci within another lambda expression, you can finally enjoy a fully recursive lambda with natural syntax:\nauto fibonacci_impl = [](const auto\u0026amp; self, int n) -\u0026gt; long { return n \u0026lt; 2 ? n : self(self, n-1) + self(self, n-2); }; auto fibonacci = [\u0026amp;fibonacci_impl](int n){ return fibonacci_impl(fibonacci_impl, n); }; std::cout \u0026lt;\u0026lt; fibonacci(10);In fact, this technique is so useful that you might be tempted to write a specialized, generic function that makes other functions recursive:\ntemplate \u0026lt;typename F\u0026gt; auto make_recursive(F\u0026amp;\u0026amp; f){ return [f=std::forward\u0026lt;F\u0026gt;(f)](auto\u0026amp;\u0026amp;...args){ return f(f, std::forward\u0026lt;decltype(args)\u0026gt;(args)...); }; }And just like that, we rediscovered what is essentially the Y-combinator idea. This higher-order function allows us to make recursive functions in languages that don\u0026rsquo;t support them directly. It doesn\u0026rsquo;t look very appealing because of the lack of explicit type parameters in C++14 lambdas, so let\u0026rsquo;s rewrite it in C++20, which supports fully fledged templates for lambda expressions. Better yet, let\u0026rsquo;s turn everything into lambdas!\nauto y_comb = []\u0026lt;typename F\u0026gt;(F\u0026amp;\u0026amp; f) -\u0026gt; decltype(auto) { return [f=std::forward\u0026lt;F\u0026gt;(f)]\u0026lt;typename...Args\u0026gt;(Args\u0026amp;\u0026amp;...args) -\u0026gt; decltype(auto) { return f(f, std::forward\u0026lt;Args\u0026gt;(args)...); }; }; auto fibonacci = y_comb(fibonacci_impl); std::cout \u0026lt;\u0026lt; fibonacci(10);I agree, it looks intimidating at first, so let\u0026rsquo;s dissect it. y_comb is a lambda that takes a generic function object, like fibonacci_impl, and returns another lambda. When you call y_comb, you\u0026rsquo;ll get this lambda back. Consequently, fibonacci in the snippet above is nothing but the lambda returned by y_comb. This returned lambda does all the work. First, it captures the function object f passed to y_comb. f is forwarded in its capture list, meaning that it will be either copied or moved into the capture. To support any scenario, the returned lambda accepts a parameter pack as its argument. As a result, it can take any number of arguments, ranging from zero to whatever seems reasonable. Those arguments are forwarded to the captured f when it is called, making for a transparent experience. You could go one step further and implement y_comb using std::invoke:\nauto y_comb = []\u0026lt;typename F\u0026gt;(F\u0026amp;\u0026amp; f) -\u0026gt; decltype(auto) { return [f=std::forward\u0026lt;F\u0026gt;(f)]\u0026lt;typename...Args\u0026gt;(Args\u0026amp;\u0026amp;...args) -\u0026gt; decltype(auto) { return std::invoke(f, f, std::forward\u0026lt;Args\u0026gt;(args)...); }; };But this is just a matter of taste, and the previous version should work just fine.\nGoing self-sufficient with C++23 #The story doesn\u0026rsquo;t end here. As it turns out, support for explicit recursive lambdas was on many wish lists. The ideas ranged from just allowing recursive calls to operator() to specialized syntaxes like:\nauto fibonacci = []internal_name(int n) -\u0026gt; long { return n \u0026lt; 2 ? n : internal_name(n-1) + internal_name(n-2); };None of those ideas made it through, though, because there was a bigger fish to catch. It materialized in C++23 as a core-language feature: deducing this. Simply put, deducing this introduces the ability to have an explicit this parameter in member functions. The current object instance, this, has always been invisibly passed to all non-static member functions, but now you can make this visible and extremely usable. Compare the two operators below:\nstruct fibonacci { // implicit this passed long operator()(int n) const { return n \u0026lt; 2 ? n : operator()(n-1) + operator()(n-2); } // explicit this passed as `self` long operator()(this const fibonacci\u0026amp; self, int n) const { return n \u0026lt; 2 ? n : self(n-1) + self(n-2); } };The second version uses the explicit this parameter syntax introduced in C++23. In the scope of operator(), the current object is known as self, and it can be used to make a recursive call instead of operator().\nHow does it help with lambdas? The really powerful idea in deducing this is embedded within the first word, deducing. The type of this doesn\u0026rsquo;t need to be specified; it can be deduced by the compiler. Applying this idea to lambdas, you\u0026rsquo;ll get:\nOpen in CEauto fibonacci = [](this const auto\u0026amp; self, int n) -\u0026gt; long { return n \u0026lt; 2 ? n : self(n-1) + self(n-2); };Clear, concise, and it works just fine.\n","date":"2026-06-12","permalink":"https://dev0notes.com/posts/2026-06-12-recursive_lambdas/","section":"Posts","summary":"\u003cp\u003eThere are algorithms that have a natural \u003cem\u003erecursive\u003c/em\u003e representation and are very cumbersome or painful to write iteratively. With the advent of lambda expressions in C++11, it seemed only natural that they should support recursive calls. But reality hit hard: recursion and lambdas didn\u0026rsquo;t mix at all until C++14, and even then the support was far from programmer-friendly. The newest C++ edition finally brings the possibility of creating a recursive lambda to the table.\u003c/p\u003e","title":"Recursive lambdas in C++"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/","section":"Tags","summary":"","title":"Tags"},{"content":" hic sunt litterae et programmata\u0026hellip; ","date":null,"permalink":"https://dev0notes.com/","section":"Welcome to /dev/null notes","summary":"\u003cdiv class=\"lead !mb-9 text-xl\"\u003e\n  hic sunt litterae et programmata\u0026hellip;\n\u003c/div\u003e","title":"Welcome to /dev/null notes"},{"content":"C++26 added static reflection to the already big bag of compile-time features. One of the most powerful tools that made it into the language is the ability to use custom annotations and to inspect them at compile time. Here, we will see how to define and use annotations, and how to pass various arguments to them that can be extracted through reflection.\nIntroduction #The main focus of the proposal introducing reflection to C++26, P2996, is inspection of programs. No matter how appealing inspecting programs may sound, being able to generate code based on inspection results sounds even better. One of the tools that aids code generation is the ability to decorate various entities in a program with custom annotations. Proposed in P3394, annotations allow for this:\nstruct [[=streamable]] Data { int id; std::string text; };Here [[=streamable]] annotates the Data type. Annotations borrow the syntax from C++ attributes, with the distinction that they always start with the character =. Crucially, annotations are values, not types. This follows the spirit of C++26 reflection, which is heavily value-oriented, as opposed to traditional type-oriented metaprogramming. This means that streamable in the example above must be an existing object. So let\u0026rsquo;s create it to make the snippet above compile:\nOpen in CEstruct streamable_t {}; constexpr streamable_t streamable{}; struct [[=streamable]] Data { int id; std::string text; };Extracting information about annotations #It should compile just fine, but doesn\u0026rsquo;t do much besides this. Let\u0026rsquo;s extend the program to finally make use of reflection and create an overloaded stream output operator at compile time for any type that\u0026rsquo;s annotated with [[=streamable]].\nOpen in CE#include \u0026lt;iostream\u0026gt; #include \u0026lt;meta\u0026gt; struct streamable_t {}; constexpr streamable_t streamable{}; template \u0026lt;typename T\u0026gt; concept Streamable = !annotations_of_with_type(^^T, ^^streamable_t).empty(); template \u0026lt;Streamable T\u0026gt; std::ostream\u0026amp; operator\u0026lt;\u0026lt;(std::ostream\u0026amp; out, T const\u0026amp; obj) { out \u0026lt;\u0026lt; \u0026#34;Yes, it streams!\\n\u0026#34;; return out; } struct [[=streamable]] Data { int id; std::string text; }; int main() { Data data{42, \u0026#34;Hello\u0026#34;}; std::cout \u0026lt;\u0026lt; data; }We introduced an overloaded operator\u0026lt;\u0026lt; function template. Soon, it will be able to enumerate over the members of obj and send them to the output stream out. But for now we must constrain it, so it will only be selected for types that have the [[=streamable]] annotation. For this we use the Streamable concept that uses reflection to check the annotations of the type passed to it. The reflection part comes in the form of a metafunction std::meta::annotations_of_with_type. Metafunctions from the meta namespace operate on an opaque type std::meta::info that represents a reflection. To get a reflection, we use the reflection operator ^^. It takes some entity (e.g., a type or a variable name) and produces its reflection as an object of type std::meta::info. Conceptually, it\u0026rsquo;s something like this:\nauto operator^^(auto\u0026amp;\u0026amp; entity) -\u0026gt; std::meta::info;All the std::meta functions are ADL-enabled, which means that we do not need to spell out their fully qualified names in most situations.\nWe used this fact when defining the Streamable concept. In it, the function annotations_of_with_type takes two reflections as its parameters: the reflection of some entity and the reflection of a type. It then returns a vector with the reflections (std::vector\u0026lt;std::meta::info\u0026gt;) of all annotations with this type that are applied to the entity. Because it\u0026rsquo;s just a vector, we can check if it\u0026rsquo;s not empty and be done with implementing the Streamable concept. What\u0026rsquo;s left is implementing the operator itself.\nReflection-based metaprogramming #We\u0026rsquo;ll start small and just print the name of the type to the output stream. To get the name, we\u0026rsquo;ll use yet another metafunction, std::meta::identifier_of. It takes a reflection and returns the name of the entity as a string:\ntemplate \u0026lt;Streamable T\u0026gt; std::ostream\u0026amp; operator\u0026lt;\u0026lt;(std::ostream\u0026amp; out, T const\u0026amp; obj) { auto sep = \u0026#34;\\n \u0026#34;; out \u0026lt;\u0026lt; identifier_of(^^T) \u0026lt;\u0026lt; \u0026#34;\\n{\u0026#34;; // print the members here return out \u0026lt;\u0026lt; \u0026#34;\\n}\u0026#34;; }Once again, we relied on the ADL lookup to call identifier_of without the std::meta:: prefix. With the name of the type printed, we can move on to the members. These can be obtained with the nonstatic_data_members_of metafunction:\nauto members = nonstatic_data_members_of(^^T, std::meta::access_context::unchecked());The second parameter specifies the access level. Here we use std::meta::access_context::unchecked(), which basically means that we ignore any access specifiers and get all the members. Yes, including those that are private or protected. This might sound like going around the access-control rules, but reflection was deliberately designed with this ability in mind. How else would we be able to write a generic debug-info dumper? Whenever you see the unchecked access context, you should be extra careful. unchecked screams at you that something dangerous is being cooked up, so you need to pay attention. If we wanted to respect the rules and only get the members we have access to, we could have used std::meta::access_context::current() instead.\nYou might think that, with the members in hand, what\u0026rsquo;s left is just iterating over them and printing their names and values. Unfortunately, this is far from what\u0026rsquo;s waiting ahead. members is a vector of reflections (yes, a std::vector\u0026lt;std::meta::info\u0026gt;) and as such it can only exist at compile time. It simply cannot pass the barrier between compile time and runtime. This means that we cannot just iterate over it and print the members. Instead, we need to:\nPromote the vector to static storage, so it can be used in a constexpr context. Use templates to expand the promoted vector at compile time and generate printing code for each member. For the first part, we can use the std::define_static_array function, proposed with its friends in P3491. It takes a compile-time sequence and auto-magically turns it into a static storage sequence (or std::span to be more precise) usable at runtime. So we\u0026rsquo;ll do:\nauto members = std::define_static_array( nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()));Expansion statements to the rescue #Now, we could use standard sequence expansion tricks, possibly heavily leaning on std::integer_sequence to print all the members. But this would be against the spirit of modern C++ metaprogramming. It\u0026rsquo;s time to bring out the big guns, the expansion statements. Simply put, it\u0026rsquo;s a compile-time sequence expansion in the form of a for-loop. Given this:\ntemplate for (constexpr auto\u0026amp; obj : some_sequence) { call_some_function(obj.do_something()); }The compiler will (roughly speaking) expand it into:\n{ constexpr auto\u0026amp; obj0 = some_sequence[0]; call_some_function(obj0.do_something()); } { constexpr auto\u0026amp; obj1 = some_sequence[1]; call_some_function(obj1.do_something()); } // and so on for all the elements in some_sequence This is precisely what we need! Equipped with the right tools, we can finally write:\nOpen in CEtemplate \u0026lt;Streamable T\u0026gt; std::ostream\u0026amp; operator\u0026lt;\u0026lt;(std::ostream\u0026amp; out, T const\u0026amp; obj) { auto sep = \u0026#34;\\n \u0026#34;; out \u0026lt;\u0026lt; identifier_of(^^T) \u0026lt;\u0026lt; \u0026#34;\\n{\u0026#34;; template for (constexpr auto member : std::define_static_array( nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) { if constexpr (has_identifier(member)) { out \u0026lt;\u0026lt; sep \u0026lt;\u0026lt; identifier_of(member) \u0026lt;\u0026lt; \u0026#34;: \u0026#34; \u0026lt;\u0026lt; obj.[: member :]; sep = \u0026#34;,\\n \u0026#34;; } } return out \u0026lt;\u0026lt; \u0026#34;\\n}\u0026#34;; }The most interesting among the added lines is the one with the splice expression, obj.[: member :]. Splicing is used to turn a reflection back into what it represents. In our case, member is a reflection of a non-static data member, so splicing it brings back the member, which can be directly used to access the corresponding subobject of obj. What makes splicing even more interesting is that it totally doesn\u0026rsquo;t care about the access level of the member. Remember that we already took care of the access when we obtained the members with the unchecked access context. Splicing is perfectly oblivious to access-control rules and will happily access private and protected members (as long as you have their reflections, of course).\nAs a side note, we guard against compile-time errors that could be triggered by members with no identifiers (e.g., bit fields with no names) with the use of if constexpr. The beauty of this approach is that the check is performed at compile time and nothing at all will be generated for members that do not have identifiers.\nAnd that\u0026rsquo;s all! In a few lines of code, we have implemented a fully generic stream output operator using reflection. See it working on Compiler Explorer.\n","date":"2026-06-06","permalink":"https://dev0notes.com/posts/2026-06-06_annotations/","section":"Posts","summary":"\u003cp\u003e\u003cem\u003eC++26\u003c/em\u003e added static reflection to the already big bag of compile-time features. One of the most powerful tools that made it into the language is the ability to use custom annotations and to inspect them at compile time. Here, we will see how to define and use annotations, and how to pass various arguments to them that can be extracted through reflection.\u003c/p\u003e","title":"Annotations in C++26 static reflection"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/c++26/","section":"Tags","summary":"","title":"C++26"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/metaprogramming/","section":"Tags","summary":"","title":"Metaprogramming"},{"content":"","date":null,"permalink":"https://dev0notes.com/tags/reflection/","section":"Tags","summary":"","title":"Reflection"},{"content":" hic sunt dracones\u0026hellip; Hi, I\u0026rsquo;m Dawid Zalewski. I can read code reasonably well and (somewhat worse) write it. Mostly in C++ and in C. But occasionally I also venture into the likes of Python, Rust, Bash, Haskell and others. This site collects my loose thoughts and results of investigations down the rabbit hole on things I find interesting. Normally, these would end up in /dev/null, hence the name.\nI thrive on abstractions, elegant and efficient code, learning language intricacies and system internals. I also like sharing what I\u0026rsquo;ve learned with others. So much that I teach programming professionally at Saxion University of Applied Sciences in Enschede, The Netherlands, and occasionally give talks at conferences.\nYou can find me on LinkedIn or drop me a message at zaldawid[at]gmail.com. (Replace [at] with @ to make the email address work.)\nThere\u0026rsquo;s nothing more to see here\u0026hellip; maybe later 👀\n","date":null,"permalink":"https://dev0notes.com/pages/about/","section":"Pages","summary":"\u003cdiv class=\"lead !mb-9 text-xl\"\u003e\n  hic sunt dracones\u0026hellip;\n\u003c/div\u003e\n\n\u003cp\u003eHi, I\u0026rsquo;m Dawid Zalewski.\nI can read code reasonably well and (somewhat worse) write it. Mostly in C++ and in C. But occasionally I also venture into the likes of Python, Rust, Bash, Haskell and others. This site collects my loose thoughts and results of investigations \u003cem\u003edown the rabbit hole\u003c/em\u003e on things I find interesting. Normally, these would end up in \u003ca href=\"https://nl.wikipedia.org/wiki//dev/null\" target=\"_blank\" rel=\"noreferrer\"\u003e\u003ccode\u003e/dev/null\u003c/code\u003e\u003c/a\u003e, hence the name.\u003c/p\u003e","title":"About"},{"content":"","date":null,"permalink":"https://dev0notes.com/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"","date":null,"permalink":"https://dev0notes.com/drafts/","section":"Drafts","summary":"","title":"Drafts"},{"content":"","date":null,"permalink":"https://dev0notes.com/pages/","section":"Pages","summary":"","title":"Pages"},{"content":"","date":null,"permalink":"https://dev0notes.com/series/","section":"Series","summary":"","title":"Series"},{"content":"Occasionally, I give talks on topics related to the technicalities of C++, C, systems programming and software development in general. Here you\u0026rsquo;ll find a list with recordings and slides from my past talks.\n▸ Lambdas\u0026ndash;the good, the bad, and the tricky at Meeting C++ 2019 #📰 Slides 📺 Sadly, because of an equipment malfunction, a recording of this talk is not available. 😞 ▸ Structured bindings uncovered at C++ on Sea 2020 #📰 Slides 📺 Recording of the session ▸ Lambdas, uses and abuses at Meeting C++ 2020 #📰 Slides 📺 Recording of the session ▸ Modern C on Sea, a half-day workshop on modern C, at C++ on Sea 2021 #This was a workshop, so there\u0026rsquo;s no recording or slides available. ▸ To pass and return\u0026ndash;the story of functions, values and compilers at Meeting C++ 2021 #📰 Slides 📺 Recording of the session ▸ To pass and return\u0026ndash;the story of functions, values and compilers at C++ on Sea 2022 #This is an updated and modified version of the talk I gave at Meeting C++ 2021.\n📰 Slides 📺 Recording of the session\n▸ Lambdas\u0026ndash;how to capture everything and stay sane at Meeting C++ 2022 #One more talk about lambdas at Meeting C++. It becomes a tradition of sorts:).\n📰 Slides 📺 Recording of the session\n▸ C is great! Long live C! at ACCU 2023 #A somewhat unusual talk about modern C.\n📰 Slides 📺 Recording of the session\n▸ Taming lambdas\u0026rsquo; uniqueness at Meeting C++ 2023 #Every lambda in C++ has a unique type. This comes with some interesting consequences. This talk is about how to work around this limitation and make lambdas more flexible in a variety of situations.\n📰 Slides 📺 Recording of the session\n▸ C++ common knowledge, once more at Meeting C++ 2023 #Aimed at beginners, this talk is about things every C++ developer should know. The talk is a story of refactoring a simple program to remove mistakes that are a consequence of misunderstanding some basic C++ concepts.\n📰 Slides 📺 Recording of the session\n▸ Magic powers at your fingertips\u0026ndash;Boosting your developer\u0026rsquo;s mojo with GDB at ACCU 2024 #Again an unusual topic at ACCU. A talk about GDB, the GNU debugger. It\u0026rsquo;s a powerful tool that can help you understand your code better and find bugs faster. The talk is about how to use GDB effectively and how to make the most of its features.\nI know Ctrl+L can refresh the screen in GDB. Learned it directly from the audience during the talk. Thanks! No idea how I missed that one. 😄\n📰 Slides 📺 Recording of the session\n▸ A kaleidoscope of lambdas at Cpp on Sea 2024 #*Yet another talk about lambdas. It was presented as a part of the Back to the basics informal track, so it\u0026rsquo;s very beginner-friendly.\n📰 Slides 📺 Recording of the session\n▸ Beginner\u0026rsquo;s Mind, Expert\u0026rsquo;s Mind at CppNorth 2024 #A talk about how we read, write and understand code. And how our brains make sense of it.\n📰 Slides 📺 Recording of the session\n","date":null,"permalink":"https://dev0notes.com/pages/talking/","section":"Pages","summary":"\u003cp\u003eOccasionally, I give talks on topics related to the technicalities of C++, C, systems programming and software development in general.\nHere you\u0026rsquo;ll find a list with recordings and slides from my past talks.\u003c/p\u003e\n\u003ch4 id=\"-lambdas-at-meeting-c-2019\" class=\"relative group\"\u003e▸ \u003cem\u003eLambdas\u0026ndash;the good, the bad, and the tricky\u003c/em\u003e at \u003ca href=\"https://meetingcpp.com/2019/\" target=\"_blank\" rel=\"noreferrer\"\u003eMeeting C++ 2019\u003c/a\u003e \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-lambdas-at-meeting-c-2019\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h4\u003e\u003cspan class=\"indent\"\u003e📰 \u003ca href=\"/slides/2019_meeting_cpp_lambdas.pdf\" title=\"Slides\" target=\"_blank\" rel=\"noreferrer\"\u003eSlides\u003c/a\u003e\n\u003c/br\u003e\n📺 Sadly, because of an equipment malfunction, a recording of this talk is not available. 😞\u003c/span\u003e\n\u003ch4 id=\"-structured-bindings-uncovered-at-c-on-sea-2020\" class=\"relative group\"\u003e▸ \u003cem\u003eStructured bindings uncovered\u003c/em\u003e at \u003ca href=\"https://cpponsea.uk/2020/\" target=\"_blank\" rel=\"noreferrer\"\u003eC++ on Sea 2020\u003c/a\u003e \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-structured-bindings-uncovered-at-c-on-sea-2020\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h4\u003e\u003cspan class=\"indent\"\u003e📰 \u003ca href=\"/slides/2020_cpp_on_sea_structured_bindings.pdf\" title=\"Slides\" target=\"_blank\" rel=\"noreferrer\"\u003eSlides\u003c/a\u003e\n\u003c/br\u003e\n📺 \u003ca href=\"https://www.youtube.com/watch?v=uZCvz-E1heA\" target=\"_blank\" rel=\"noreferrer\"\u003eRecording of the session\u003c/a\u003e\u003c/span\u003e\n\u003ch4 id=\"-lambdas-uses-and-abuses-at-meeting-c-2020\" class=\"relative group\"\u003e▸ \u003cem\u003eLambdas, uses and abuses\u003c/em\u003e at \u003ca href=\"https://meetingcpp.com/2020/\" target=\"_blank\" rel=\"noreferrer\"\u003eMeeting C++ 2020\u003c/a\u003e \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-lambdas-uses-and-abuses-at-meeting-c-2020\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h4\u003e\u003cspan class=\"indent\"\u003e📰 \u003ca href=\"/slides/2020_meeting_cpp_lambdas.pdf\" title=\"Slides\" target=\"_blank\" rel=\"noreferrer\"\u003eSlides\u003c/a\u003e\n\u003c/br\u003e\n📺 \u003ca href=\"https://www.youtube.com/watch?v=Onv9w6FGwIQ\" target=\"_blank\" rel=\"noreferrer\"\u003eRecording of the session\u003c/a\u003e\u003c/span\u003e\n\u003ch4 id=\"-modern-c-on-sea-a-half-day-workshop-on-modern-c-at-c-on-sea-2021\" class=\"relative group\"\u003e▸ \u003cem\u003eModern C on Sea\u003c/em\u003e, a half-day workshop on modern C, at \u003ca href=\"https://cpponsea.uk/2021/\" target=\"_blank\" rel=\"noreferrer\"\u003eC++ on Sea 2021\u003c/a\u003e \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-modern-c-on-sea-a-half-day-workshop-on-modern-c-at-c-on-sea-2021\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h4\u003e\u003cspan class=\"indent\"\u003e\u003cem\u003eThis was a workshop, so there\u0026rsquo;s no recording or slides available.\u003c/em\u003e\u003c/span\u003e\n\u003ch4 id=\"-to-pass-and-return-at-meeting-c-2021\" class=\"relative group\"\u003e▸ \u003cem\u003eTo pass and return\u0026ndash;the story of functions, values and compilers\u003c/em\u003e at \u003ca href=\"https://meetingcpp.com/2021/\" target=\"_blank\" rel=\"noreferrer\"\u003eMeeting C++ 2021\u003c/a\u003e \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-to-pass-and-return-at-meeting-c-2021\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h4\u003e\u003cspan class=\"indent\"\u003e📰 \u003ca href=\"/slides/2021_meeting_cpp_to_pass_and_return.pdf\" title=\"Slides\" target=\"_blank\" rel=\"noreferrer\"\u003eSlides\u003c/a\u003e\n\u003c/br\u003e\n📺 \u003ca href=\"https://www.youtube.com/watch?v=lxg-HWZvHEI\" target=\"_blank\" rel=\"noreferrer\"\u003eRecording of the session\u003c/a\u003e\u003c/span\u003e\n\u003ch4 id=\"-to-pass-and-return-at-c-on-sea-2022\" class=\"relative group\"\u003e▸ \u003cem\u003eTo pass and return\u0026ndash;the story of functions, values and compilers\u003c/em\u003e at \u003ca href=\"https://cpponsea.uk/\" target=\"_blank\" rel=\"noreferrer\"\u003eC++ on Sea 2022\u003c/a\u003e \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-to-pass-and-return-at-c-on-sea-2022\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h4\u003e\u003cspan class=\"indent\"\u003e\u003cp\u003e\u003cem\u003eThis is an updated and modified version of the talk I gave at \u003ca href=\"https://meetingcpp.com/2021/\" target=\"_blank\" rel=\"noreferrer\"\u003eMeeting C++ 2021\u003c/a\u003e.\u003c/em\u003e\u003c/p\u003e","title":"Talking"}]