Skip to main content

Posts

Showing posts from 2018

Chained Functions Break Reference Lifetime Extension

I discovered a reference lifetime extension gotcha.

TL;DR; Chained functions (that return a reference to *this) do not trigger C++ reference lifetime extension. Have all chained functions return *this by-value or have a last chained LifetimeExtend() function that returns a prvalue (of type *this). C++ Reference Lifetime Extension C++ has a feature called "reference lifetime extension". Consider the following. std::array<std::string, 5> create_array_of_strings(); { const std::array &arr = create_array_of_strings(); // Only inspect arr here. } // arr out of scope. The temporary pointed to by arr destroyed here. The temporary std::array returned by create_array_of_strings() is not destroyed after the function returns. Instead the "lifetime" of the temporary std::array is extended till the end of lifetime of reference arr. This feature saves you from coping the object when all you want to do is to inspect it's state. Without this feature, the std…

Convenient deduction guides for std::function

The objective is to allow the following to be valid C++. #include <functional> struct Test { void func(int) {} }; void test() { std::function deduced = &Test::func; // compiler error std::function<void (Test *, int)> ex = &Test::func; // OK } With class template argument deduction in C++17, type arguments for std::function above should have been deduced. The first line in function testfails to compile as of this writing because std::function does not appear to have deduction guides for conversion from pointer to member functions. On the other hand, explicitly specifying the template arguments makes the compiler happy.

The following deduction guide seems to fix the issue. namespace std { // warning: undefined behavior template<class R, class C, class... ArgTypes> function(R(C::*)(ArgTypes...)) -> function<R(C*, ArgTypes...)>; } void test() { std::function deduced = &Test::func; // Now, OK std::function<void (Test *, int)&…

Inheritance vs std::variant

C++17 added std::variant and std::visit in its repertoire. They are worth a close examination. I've been wondering about whether they are always better than inheritance for modeling sum-types (fancy name for discriminated unions) and if not, under what circumstances they are not. We'll compare the two approaches in this blog post. So here it goes.

Inheritancestd::variantNeed not know all the derived types upfront (open-world assumption)Must know all the cases upfront (closed-world assumption)Dynamic Allocation (usually)No dynamic allocationIntrusive (must inherit from the base class)Non-intrusive (third-party classes can participate)Reference semantics (think how you copy a vector of pointers to base class?)Value semantics (copying is trivial)Algorithm scattered into classesAlgorithm in one placeLanguage supported (Clear errors if pure-virtual is not implemented)Library supported (poor error messages)Creates a first-class abstractionIt’s just a containerKeeps fluent interfaces…