Jonathan Boccara's blog

How to Make SFINAE Pretty – Part 2: the Hidden Beauty of SFINAE

Published May 18, 2018 - 10 Comments

Before we start again, have you sent in yet your most beautiful piece of code that prints 42? Towel day is coming up, so join in the celebration!!

Now that is said again, we can start ūüôā

As we’ve seen in¬†How to Make SFINAE Pretty – Part 1: What SFINAE Brings to Code, SFINAE in code is as pretty as a windmill in a field. That is, not very pretty.

But like a windmill, it’s useful. SFINAE helps deactivate a piece of template code depending on a condition, and that can be very convenient.

For instance, our motivating example was to remove the second overload of this class template, in the case where T is a reference (because in that case, it prevent the class from compiling):

And we ended up with an expression that works, but whose appearance is a slight to those who love to look at beautiful code:

If you’re not sure about how this works exactly, have a look at Part 1.

Now let’s put some makeup over that poor expression, to make it look presentable in our code.

To do this, we’ll use amongst others some techniques that Stephen Dewhurst has presented in his talk¬†Modern C++ Interfaces.

SFINAE pretty C++ enable_if template

This post is part on the series on SFINAE:

*_t, *_v and {}

One of the burdens of the SFINAE expression is all the little things such as ::type, typename¬†and ::value¬†that don’t add any meaning to the expression, but are there for technical reasons. Let’s see how to get rid of them.

*_t

C++14 adds a variation of std::enable_if: std::enable_if_t. It is just an alias for accessing the ::type inside std::enable_if. Its implementation is this:

Since it is based on template aliases, this implementation is also compliant with C++11. So if you’re not in C++14 but in C++11 only,¬† you can just an implementation like the one above.

std::enable_if_t allows for a shorter syntax:

as opposed to:

In fact, the other template classes that have a ::type in the standard library also get a _t counterpart in C++14. This includes std::decay_t and std::conditional_t for example.

*_v

In a similar way, the templates that contain a ::value, such as std::is_reference or std::is_const, get a *_v counterpart in C++17.

Their implementation looks like this:

This uses both a feature of C++14 (variable templates) and of C++17 (inline variables).

By using these features (depending on which version of C++ you have at hand), our SFINAE expression can be reduced from this:

down to this:

{}

If you have C++11 (and not C++14 or C++17), you can still shorten the is_reference bit of the expression, by instantiating it with braces {} inside the template call:

The bit we focus on here is this:

This instantiates a value of type std::is_reference<T_>, which inherits from std::true_type (respectively to std::false_type, depending on whether T_ is a reference or not). And std::true_type (resp. std::false_type) is implicitly convertible to bool, giving out the value true (resp. false). Thanks to Vittorio Romeo that took the time to explain this to me on his website.

A place where SFINAE won’t get in the way

Here is an idea that Stephen Dewhurst has presented in one of his inspiring talks at CppCon: Modern C++ Interfaces. This talks contains lots of insights and changed my way of coding template interfaces. I recommend that you watch it.

C++11 introduced default template parameters for functions (and class methods) templates. Indeed, in C++98, only class templates could have default values for template types:

And in C++11 we can also write:

In fact, if we don’t use this parameter in the body of the function, we can even omit its name:

What would be the point of such a template parameter that we can’t use?

Well, it can host our SFINAE expression! Indeed, since we can put any type in a template parameter, including void, we don’t have to resort to finding a dummy type like nullptr_t for resolving the SFINAE. Conveniently enough, std::enable_if¬†has a default value for its underlying type, which is¬†void.

So our SFINAE expression is now reduced from this:

to this:

And its position in the overload would be this:

Encapsulating the technical machinery

We could arguably stop here, but there is still a layer of template machinery that we could remove from this interface. In his talk, Stephen Dewhurst advises to hide the enable_if expression behind a names that sums up its intent.

In our case here, such a name could be EnableIfIsNotReference, or perhaps just IsNotReference.

So let’s define an alias for the SFINAE expression that encapsulates it behind that name:

Putting it all together, our code has now become:

As a comparison, here is what we started with:

It was worth the transformation, wasn’t it? This is pretty much exactly a commit I’ve made in the NamedType library after watching Modern C++ Interfaces.

There are other ways to make other situations of SFINAE clearer, such as C++17’s¬†if_constexpr¬†inside a block of template code. But for an template interface, the above techniques are quite useful.

Related articles:

Become a Patron!
Share this post! Facebooktwittergoogle_pluslinkedin    Don't want to miss out ? Follow:   twitterlinkedinrss

Get a free ebook on C++ smart pointers

Get a free ebook of more than 50 pages that will teach you the basic, medium and advanced aspects of C++ smart pointers, by subscribing to our mailing list! On top of that, you will also receive regular updates to make your code more expressive.

No spam. You can unsubscribe at any time.

10 comments