Categories
C++Programming

Design by Introspection (C++20)

Some time ago I stumbled upon a very interesting (and for me new) technique named “Design by Introspection”, which is easily possible with the concept feature of C++20.

This technique can be illustrated by the following small code snippet:

auto value( auto v ) 
{
	// unnamed concept in constexpr if-branch!
	if constexpr ( requires { v.value; } ) {    // if type of v has a .value use this branch.
		return v.value;
	} else {
		return v;
	}
}

First the parameter of the function value is of type auto, so it will be set to a concrete type per invocation during compile time.

Now the interesting part is in line 4. If the code v.value is valid and can be compiled with the concrete type of v, the if-branch of line 4 will be used and the return value is v.value. Otherwise, v will be returned from the else branch.

Line 4 uses a requires clause in the constexpr-if, which is forming a constraint, which is checked during compile time. And because the function parameter is of type auto, the function behaves like a template-function and SFINAE is present (SFINAE = Substitution Failure Is Not An Error).

If the type of v has no valid v.value, SFINAE is the reason for that it will not lead to a compile error and the else branch is used instead.

Of course, if no branch is compilable, a compile error will occur.

So, the example function above could be called like this:

long long number = 123;

auto res = value( number ); // the v branch is used.

struct X {
    bool x = false;
    std::string name = "foo";
    long long value = 42;
} my_x;

auto res2 = value( my_x ); // the v.value branch is used.

I think with “Design by Introspection” a great way of generic programming is available in C++20. There are tons of use cases imaginable. Maybe more to this in some upcoming Blog posts.

Leave a Reply

Your email address will not be published. Required fields are marked *