Introduction to C++ Template Metaprogramming
Goldshtein, Sasha
Template metaprogramming (TMP) is an extremely important technique in modern C++. First, TMP can be used as a precursor to C++17 Concepts, in order to check constraints and produce clear error messages when a template parameter doesn't adhere to its specified constraints. Second, TMP can be used to pick an algorithm implementation based on the template type provided - thus enabling optimizations for specific types. Finally, TMP can be used to introspect C++ types at compile-time and generate compile-time constructs that save time or enable fully-compile-time computation. In this talk, we will review a collection of techniques and examples for using TMP in your libraries and application code. You are expected to understand basic template syntax and template specialisation, and we will build the rest as we go along.
 So basically building contracts for your APIs, making sure certain properties of types are met before your API is invoked and can do stuff at runtime. The other thing is member detection. So basically building your own type checkers, which verify that certain types have certain properties, have certain members, have certain subtypes. Then we have algorithm selection. So basically we'll specialize a certain algorithm, such as an STL algorithm or one of our own, based on the type properties that we detect. So there's a bunch of examples, and I'll show you a couple. And finally, towards the end, there's a couple of examples of compile time computation with constexpr, which really allows for a lot simpler type checking and a lot simpler computation where you'd have to use recursive templates and a bunch of complex stuff before. I'm going to just be using a lot of examples, and most of the stuff I'm doing here requires C++11. It should work with any C++11 conformant compiler, maybe except for Visual C++, which still has some incompatibilities. Some of the code requires C++14, but it can be rewritten to only require 11. And without some features such as decal type, which were introduced in C++11, it's quite hard or anyway harder to implement some of the things I'm going to talk about, and some are even impossible, actually, with the older version of the standard. So some motivation and examples. Here's an example of a situation where constrained checking could actually be useful. So if you're sitting in the back, you can't even read this whole thing. But this is basically what happened when I just launched Xcode, built a little C++ project, and tried to use as a map key a type that doesn't have the less than operator. So I built an STD map, and the key is a type that doesn't have the less than operator. Now just declaring a map like that, as you probably know, doesn't cause any issues in compilation time. However, trying to use it, so once I try and insert an element into the map with a certain key, that blows up. And this is just a very small part of the actual compiler error message that I received. But one thing to note is that the error is coming from Clang in this case. It's pretty decent, so it's telling me invalid operands to binary expression less than, where I am trying to invoke less than on values of type const foo, and foo is the key type in my map, which doesn't have the less than operator. But then if you look at some of the further notes emitted by the compiler, there's a bunch of nonsense here. So why do I care about something called a tree with a value compare, and if you look a little lower, it has some ridiculous stuff about not being able to match the operator less than for pairs of whatever. So if you're an experience C++ developer, you've seen this error before, and you know that you just forgot to declare less than operator, so your keys are invalid. But for less seasoned developers, this is very troubling. And they can spend a while just posting this thing to stack overflow and getting flamed by everyone. So better error checking, for example, in the STL could be really helpful if at compile time we could get a nice error message that says, well, in addition to all these other problems, it is likely that what you forgot to do is just to declare less than or specialize STD less for your type and just move forward. So the other example I've mentioned is algorithm selection, where you have multiple versions of an algorithm that can be more performant, more efficient for certain types. Here's a couple of classic examples from the STL, which a lot of STL implementations actually use. So STD copy can be specialized if the thing we are copying is a plain old data type, doesn't have any sophisticated assignment behavior, and you're copying from pointer ranges, not iterators. So if you basically have a mem copy situation and you are allowed to just optimize and use mem copy instead of the slower loop version of STD copy, that can be a considerable performance gains for certain types. Another example is STD distance, and distance, as you know, finds the number of elements in a range between two iterators. So for certain iterators, such as random access iterators, it can be implemented in constant time, O of 1, right? And for, say, forward only iterators, you'd have to actually traverse the iterator so you'd have an O of n, a linear time implementation. So that's another example of where figuring out some information about the type could help optimize an algorithm, select the right algorithm at compile time. And then another example, as I said, is compile time computation. So certain things can be pre-computed at compile time or solved entirely at compile time. One example that I really hope to show you towards the end is string validation. So if the user provides a literal string as an input to a certain function, we could check that that string has certain properties at compile time instead of throwing an exception at runtime. And for certain APIs, such as maybe printf, right, it can be useful to emit errors as early as possible at compile time instead of deferring to runtime. So there's a bunch of users which hopefully illustrate this is a practical thing to talk about, even though not the most practical in the world. The main tool we'll be using throughout this talk is template specialization. So this is just a very, very quick reminder of how this works, what it looks like. So basically here we have a partial and an explicit complete specialization of the less template. So less has an operator that can be invoked as a function, and it compares two objects, determines which one should be sorted before the other. We also have a specialization for pointers here, which compares not the pointers, but compares the targets, right, the pointees, the things the pointers are pointing to. And finally we have a complete explicit specialization for a char pointer where we use strCmp. So we're not comparing the char's, we're not comparing the pointers either, we are comparing the whole string until the null terminator. So that's just the tool we're going to be using, and hopefully you're all familiar with that, but it never hurts to just see a quick example. So let's start with constraint checking. As you probably know, in the standard library there's a header type traits, which has a bunch of useful meta functions which take types and return in some cases values, in some cases types. Meta functions basically operate at compile time on types and produce either values like Booleans, for example, does a type have a certain property, or other types. So for example, you could have a meta function that takes a type and adds a reference to it. So it produces the same type, but with a reference added at the end, or removes const from a type, that kind of thing. A lot of these can actually be implemented pretty easily, so if you're looking for exercises on meta functions, you can implement a lot of these type traits yourself. There's a lot of corner cases to take care of, but you could. A lot of these, however, cannot be implemented without actual compiler support. So the standard library implementation on a particular platform would have to ask the compiler for hooks, which implement some of these type traits, because there's no way to express in the language itself checking for that kind of constraint. So some useful examples. Is pointer, for example, checks if a type is a pointer type. And it sounds easy, but if you actually look at the implementation, you have to take care of pointers to functions and pointers to members, and const pointers, and pointers to const, and a bunch of other edge cases. So it's useful to have this in the library. We have more complex traits such as is no throw copy constructable, right? So does the type T have a copy constructor which is marked no accept, and will not emit exceptions at runtime? We can use a lot of these, and we can develop some of our own type traits based on what's available in the library, and based on other techniques as well. So here's a very simple example of using a type trait. This is not a standard library situation, it's just a type I figured I want to develop. It's a class called array. There's actually std array in the standard library, but suppose that's not what we're seeing here. And my array wants to be a no throw kind of type, a no accept type. I want the constructor of the array to not throw exceptions. I want all the members actually to do the same. And so if in my array I have a statically allocated array of Ts, I would like to produce a clean error message in case that type T does not have a non-throwing default constructor. So I can mark my own class's constructor as no accept, and that will produce some error message if T doesn't meet the necessary requirements, but I actually want to go further than that, and I want a clean assertion that says exactly what happened if the user uses an incorrect type. So I can put a static assertion that uses a standard library type trait and checks explicitly that T has a default constructor, a parameter less constructor, which does not throw, which is marked no accept explicitly. Another example of using traits in a situation that's not exactly error checking, but rather sort of making sure your implementation is very accurate, is this example from swap over here. So this is STD swap pretty much with some minor changes introduced. Everyone's familiar with STD swap. And what it does inside is it tries to use move operations, right? In case the type T supports move, I wouldn't like to copy to a temporary and then copy back from the temporary, I'd rather just do moves all the way. And I would like the swap operator to be marked no accept. I would like it, but I'm not actually sure if the code inside is going to be throwing exceptions or not. I don't know in advance whether, for example, the move constructor and the move assignment operator for T are marked no accept or not. So I don't want to emit an error in that case. I don't want to place a static assert in my swap that says no. You can't use this swap function if your T is not no accept because that just is plain bad. Instead, we could, in this case, for example, use the conditional form of the no accept operator. So we could say that, OK, this function is no accept in case certain properties are met. So this is the no accept operator which takes a Boolean value that has to be known at compile time. So my swap is no accept as long as T has no throw and no accept move constructor and a no accept move assignment operator. If these two properties hold, then the code I wrote is actually going to be no accept correct. So that's just another use of constraint checking and type checking that we could introduce, even if not to emit errors, but just to make sure we're really expressing ourselves very accurately. OK, so suppose we have the basic type traits figured out, the ones that are in the standard library, but we have a unique situation of our own. We have some kind of property of a type that we want to detect, that we want to test for. One example that I often use in training workshops is determining whether a certain type is an STL container. So for example, imagine you're building a serialization framework or maybe just a debug printing framework that takes an arbitrary object and wants to print it as accurately as possible. So if the type already has an output operator, then I'll just invoke that. If the type is a container, I would like to detect it's a container and print out the contents, print out the elements of the container and do so recursively. So this can be useful for serialization, can be useful for, again, debug printouts, but the question is how is this generic template print function or serialized function is going to figure out if our type is a container or not. We'll have to have multiple implementations and pick the right one, but in order to pick, we have to ask, is this thing a container? So we could go with the formal definitions of what a container is or maybe a range if we want to work with somewhat newer concepts, but still it boils down to asking, does a type have certain properties? So for example, to be very naive, I could say a type is a container if it has a begin member function. So a bunch of types might have a begin member functions and not be containers and also arrays are containers but they don't have a member function called begin, but that would be an approximation. Or I could maybe say a type is a container if it has an nested type def called iterator, right, like vector, iterator, map, iterator and so on. So again, that wouldn't work for arrays, but it would be an approximation. And if we wanted to be super accurate, we could just ask, what do we want to do with that object if it is a container? So the answer is, okay, if it is a container, I want to enumerate all the elements in the container and then I could just test for that directly. So can I invoke begin and get something that looks like an iterator which I can increment and compare and dereference? So there's a bunch of type properties that we want to be checking. So this happens a lot, again, if you're building generic libraries that have to ask for, that have to care about the properties of the given type, sometimes just to reject certain types and in other cases to specialize your decision based on properties of a type. So let's build something that detects whether a type is a container. There's a bunch of techniques for this. Even in C++98, we could sort of ask if a type has certain members, for example, or if a type has certain nested type defs, but in C++11 with decal type and with a bunch of further advances, we have easier solutions for this problem. So again, we want to build our own type traits which ask, does a type have a certain member or more generally, does a certain expression make sense for my type? Does it compile? And even maybe does it produce a certain type as a result? So for example, not just, for example, for the dereference operator on iterators, I actually wanted to produce a value. If I have a void returning dereference operator, that's a little fishy for a container. So we want to ask if a certain expression makes sense and maybe produces a particular type. So there's a very cool trick here introduced by Walter Brown, I think a couple of years ago at CPPCon, I was very impressed when I saw it first. There's a bunch of other ways to express the same thing, but this one is so clean and so concise that I really fell in love with this technique and I've been telling about it to people since. So basically, you have this super simple and weird looking template. This is actually a Lalias template which defines void t as void for any type. So this is a template, you could say void t of int, void t of float, void t of std vector, and it's always just void. It's always defined to be void. The point is not that it is void. The point is that if we try and use this thing, if we try and use void t with a type that's not well formed, with a type that's not valid, then this thing just has no definition. The thing doesn't make sense. So void t wouldn't be sensible, whereas if we use any valid type as the template parameter here, we would get void always, just regardless of what we put in. There's alternatives for this in the standard library, but it's really clean to just see it this way. So here's how we use it for isContainer in our example. Up top, there's the first version, the more general version of the isContainer template, and it has two template type parameters, t and another one, which is unnamed, I don't care what it's called, and it has a default type parameter value which is void. So this one is the more generic template, it's not a specialization, and this one is defined to inherit from std is array of t. So basically, if we go to that isContainer template up top and we ignore everything else on the slide, then it's basically equivalent to asking is t an array. If t is an array, then this template recognizes it as a container, and if t is not an array, then we don't recognize it as a container. So we've taken care of arrays separately. And isArray, of course, is defined in type traits, and we assume it works correctly. And then we have the specialization. It's occasionally unclear why this thing is even a specialization of the first thing. So how would you convince your friends that this second definition is a specialization of the first? It has fewer type parameters. It has fewer type parameters, right? So the one up top has two type parameters, even though the second one has a default value, but the one on the bottom only has one type parameter. So that's enough for me, I suppose. And this is container template is a specialization in case, well, t, the first argument is just the t we got passed in. And the second thing, the second type parameter, which has a default value of void over here, the second type parameter is that void t template specialized, well, sorry, parameterized with t iterator, right, with the nested iterator type def. And if we use this specialization, then I just inherit from a true type to indicate that yes, we are a container. So basically, if this specialization is chosen, then we deduced that t is a container. Okay, so for this specialization to be chosen, what needs to happen is that void t of that type is well-formed. If it is not, if our type is, for example, an int, then what we have over here is just int column, column, iterator. That doesn't make sense. That's not well-formed. And then substitution failure kicks in, and we just ignore this specialization. And we have our base case, which will then deduce that int, because it's not an array, is not a container. But if t does have a nested iterator type def, then this thing over here is well-formed, and this is just plain void, right? And then this is a specialization of the previous case, and this specialization is a better match, so the compiler, when doing the template specialization pattern matching, would pick this version and deduce that our type is a container because we inherited from true type. Why, just one final thing, why does it matter that this here is void? Why did they put void in here and not something else? I was looking for the same person to answer. Yeah, no, so what I'm asking is why does this have to be void and not say int, right? Because this has to be void, and the thing that happens is if the user of my template of isContainer doesn't provide the second type, right, so my user says isContainerOfInt. The user doesn't specify what the second type is, so if the user says isContainerOfInt, I would like both versions to be potential candidates. So in this case, isContainer, the first version, would be isContainerOfT and void, and this one would be isContainerOfT and whatever void T produces. So if void T produces void, we have our two candidates, and the more specialized one can be picked. But if here, I said int, for example, then when the user says isContainerOfWhatever, then what the user actually said is isContainerWhatever,int, right, and then the second specialization would just never be valid because void T doesn't produce an int, it produces void. So all the parts here matter, right? It does matter that we have void up there, it matters that void T returns void. Everything's important in this skeleton, if you will, for member detection. Now you might ask, can this be generalized further? And yes, it can. So here, we're just testing if a type has a certain nested type def, but we can make this further generic, if you will. So if I want to test that a certain expression, arbitrary expression pretty much on arbitrary types makes sense, and that's the trait I am checking for, that's the property I'm testing for, then the general recipe would be. We define an alias template for that specific test, and it's basically just the decal type of whatever this expression returns. So suppose I want to check if T1 has a member function called foo, which takes a T2, right? So I have this alias template, which is a template in T1 and T2, and it is declared as the decal type of this expression here, which declares a value of type T1 reference, and then invokes foo on it, passing in a T2, right? And the decal val function is just a very stupid silly little function from the standard library. It has no body, it's just a declaration, because we use it in context which do not require evaluation. So it's basically just declaring T1 for us or T2 for us. That's the only thing we care about. Once we have that test, we just plug it into our skeleton. So the generic version of does my condition, is my condition true for a certain pair of types, the one over here, the generic version, takes T1 and T2 and that dummy void template parameter, and the specialization takes T1 and T2 and whatever void T returns when invoked with my test, which is up there. So if that expression makes sense, if this thing here is well formed, then void T produces void and we pick the second specialization, and if it is not well formed, then we pick the first one and we reject that property. And we could even test if we wanted that my test T is not just well formed, we could ask what kind of thing it is. So I could add, for example over here, I could add, so is my test T of T1 and T2 actually say an int or a const reference or whatever else I wanted to assert? So we basically have now a generic recipe for checking properties of types thanks to this void T trick. This again, it requires compiler support. So for example, my usual go to compiler again, which is Visual C++, still has some restrictions around expression substitution failure is not an error, expression is finite, so it would actually reject a bunch of these examples. But the more conforming compilers, GCC, Clang, they're okay with this. And Microsoft is working on fixing the edge cases that still don't work. And actually this kind of template is pretty useful in the standard library as well. So just as an example, in the standard library, there is a type trait called is assignable, which just determines whether one type can be assigned to another using the assignment operator. You could easily implement it using this generic trick, right? So over here in the decal type body, we would have just decal val A assignment, decal val B, and we'd have to test if that is well formed. So standard libraries all over the world can now use this instead of requiring compiler hooks or some sophisticated one-off tricks. There's just a generic trick that works for all the cases. So that was member detection. And once we have that, let's talk about some ways, right, some strategies for actually using the property we discovered for choosing one of multiple algorithms. Again if we want to optimize STD copy, for example, for pointers to primitive types as opposed to the general case of just iterators we know nothing about. So there's three general strategies I want to show you, which are common in a bunch of different template libraries, including the STL. One is just explicit specialization when you write all the boilerplate yourself. The other is tag dispatch, which is useful and used a lot in the STL, where you have multiple versions of an algorithm. So basically the property you're testing is not binary, true or false. It has multiple degrees of being true. And there's also STD enable if, which is usually used if you want to disable a certain function, if you want to remove a certain function from the set of overloads that you would want the compiler to consider. So let's take a look at a few examples. Again, just an overview of the tricks that a lot of libraries use. So this rather verbose thing on the screen is an attempt to specialize the sort implementation, just a general sort that takes iterators for two cases. One when the type we're sorting just has general properties, is generally comparable, right? So it has a less than operator, which provides order. And the other case is if it's hashable, if there is a way to produce hashes from values of that type. So if it is hashable, maybe I'm going to use a different sort algorithm like radix sort, and if it's not hashable, I'm going to use something else. It's just an example. I'm not saying there's a practical use of this kind of sort implementation. But we want to ask about the property of the type and then just redirect to two different implementations. So I can have this base case of a sort imple class template, which is undefined. Basically I don't care about it because I am going to have specializations for both of the cases. So this base template is a template of some type and the Boolean. And then I have two specializations. I have one for some type and false, and another for some type and true. So I basically covered all the cases because Booleans can be either true or false. So there shouldn't be any case where we actually get to the base template and the compiler would complain that we haven't actually defined it. So for false, I have one definition of a static sort function, and for true, I have a different definition of a static sort function. So basically this is just a way of picking overloads at compile time. I have two functions in two different class templates, and I'm choosing the right one based on whether some property is true or false at compile time. So now I just have to ask, is that property true? And redirect to one of the options. So in this version, which is the publicly accessible one, that's the thing that clients actually invoke. In this version, I specialize sort-imple, I parameterize sort-imple by whether the value type of that iterator has some property. So is hashable v? That's not a standard library thing, but it's a type trait that we built using the techniques we talked about previously. So sort-imple of my iterator type, and either true or false, just picks one of the two class template specializations we had over here, and then I invoke the static sort method on that passing in my iterators. So we have just successfully picked one of two implementations based on a Boolean property of some type. This is a bit verbose, but it works, and in some cases, you might actually prefer it. For example, if that type that you're using actually has to have some state and member functions, it's actually useful to just pick one of multiple class template specializations and then just work with that class template, kind of like the strategy pattern, except you're doing it in compile time and not at runtime. And this can be obviously expanded further to a bunch of additional examples. The other alternative, which is pretty common in the standard library, is tag dispatch. This doesn't require class template specialization, just multiple overloads of a certain function, and the overloads are different only by usually a trailing type which can take multiple type values. So here's a classic example from distance. This is an STD algorithm that finds the distance between two iterators, right? How many elements are in the range between two iterators? So this is the publicly accessible declaration. So distance takes two iterators. What it returns is, well, whatever iterator traits difference type is for my iterator type. So conveniently, we have iterator traits, which is supposed to tell us things about iterators. This is yet another example of a meta function that takes types and returns values and types for us. And then I invoke distance helper, which is not a publicly accessible interface, and distance helper takes the two iterators first and last, as well as an additional parameter. And this one is also obtained from iterator traits. So in iterator traits, I have iterator category, which is a type. So I instantiate that type over here, and that's what I pass to distance helper. So now distance helper can be overloaded for various types that iterator category can return. Just for simplicity, suppose iterator category is sometimes an int and sometimes a float. So I can now build two distance helpers, one that takes an int and one that takes a float as the third parameter, and in such a way specialize my implementation. Iterator category, fortunately, doesn't return int or float. It's a meta function that returns one of multiple types, indicating what kind of iterators we have on our hands. So it could be forward iterator, an input iterator, bidirectional iterator, random access iterator, and so on. And here's what the actual helper could look like. So for random access iterator tag, which is the iterator category for random access iterators, my implementation just uses the minus operator, right? So we just find the distance between the two iterators. And for anything else, this is the second version of distance helper, it takes iterator tag base, which is the base class of all the other iterator categories, of all the iterator categories. So for iterator tag base, we have the implementation here, which declares a counter and then just traverses the range, incrementing the counter till we reach last, right? So while first is not last, increment last, increment n till we get to the end and then return n. So this is going to be the linear time version, and that's going to be, hopefully, a constant time version. And we just used a property, a type property, returned by iterator category to choose one of the two. So that's a pretty common technique as well. And a third example I want to show you is an A... Just like a lot of classes. And it also has this constructor over here, which takes a universal reference to any t. And the reason you'd usually have that kind of constructor, does it work now? Okay. So the reason you'd usually have that kind of constructor, which takes a universal reference, is not to emulate a copy constructor and a move constructor on your own type, but rather to enable construction from some other type. So for example, maybe my widget, it can actually be constructed from, for example, a tuple of configuration values. And I want to optimize for two cases, one when I am passed an r-value reference, which I can move from, and the other when I'm passed a const reference to an l-value, which I can only copy from. That's a pretty common situation. But even ignore the reason why I actually have that kind of templated constructor. The issue here is hiding. What can happen is that if the user of my widget class initializes a widget and uses an l-value reference to a widget, which is not const, so basically just widget ampersand, right, an l-value reference to a widget which isn't const, then the compiler can choose between my copy constructor, which takes a const reference to a widget, and this template constructor, which was never intended for situations where t is a widget, but it would apply in that case, and it would be picked, because this constructor works where the t ref ref actually resolves to just a widget ampersand, to an l-value reference to a widget. So we have a constructor that takes a const reference and a constructor which takes a non-const reference, and that second constructor would be preferred. So essentially, we built a universal constructor which hides our own copy constructor. This is undesirable. So we can ask the compiler, essentially, to not pick that specific overload, that specific constructor, if I'm using a widget as t. So the way this typically works is that somewhere in the signature, and there's a lot of places you could actually put that in the signature, somewhere in the signature, you put enable if, and enable if is very similar to void t, actually. It just determines whether an expression is well-formed, and then it's used for substitution failure to remove that overload from the set of overloads that can be considered. So in this case, the expression I'm passing to enable if is not is same t widget reference value. So basically a Boolean which says whether or not t is the same thing as an l-value reference to a widget. So if t is the same thing as an l-value reference to a widget, this expression, because of the not here, this expression is going to be false. And then we have enable if of false, and enable if of false is not defined. So it's not a type, it's not any type, whereas enable if of true is void, kind of like our void t template. So in the case where enable if t here produces void, this template overload is considered valid, and in the case where enable if t takes false, and it is undefined, this constructor is just removed from the set of candidates because it is a substitution failure when trying to match the template arguments, the template type arguments. You could place that enable if in a bunch of additional places, maybe in, when reviewing template libraries, you might have seen enable if as an additional parameter, right? So in some cases you put it as an additional parameter which has a default null value. You could use enable if as the return type, not in a constructor though, constructors can't have declared return types, but in other functions you could use enable if t is the return type, again just to get the compiler to consider that type as part of the function's signature. Again if it doesn't match, then this signature, that overload is removed from the set of candidates that the compiler would consider. So in this way we could just disable this overload in certain circumstances, and this trick is used a lot in the STL, yeah? Is there a way to apply this trick if it's not in some kind of place? Is there a way to apply it? Without the constructor constructors? What do you mean? If you have templates like the NT of rigid and you have a copy constructor and a move constructor, and you wanted it to choose the copy constructor in the cases where it was actually copying instead of moving. As you said, the move constructor will always be preferred if it's a long const. So if you declare a copy constructor and the move constructor, then the move constructor will be chosen if you have an r-value reference, if you have a reference to a temporary, if you have a reference to an l-value, then the copy constructor will always be chosen automatically. Just think about it, your move constructor is going to be moving, so it's going to destroy the object. If you have an l-value, that would be extremely unsafe. You don't need this trick at all if you just declare a copy constructor and a move constructor and you want the compiler to pick. So in that case it doesn't actually collapse to its own reference? It was not? It didn't collapse to just a reference in that case? So you're saying no template here, no universal reference, just a copy constructor and a move constructor, right? No, I'm saying that the class is template. Oh, that's fine. And the constructors, what do they take? Do they take widgets or do they take one of the template arguments? Type name, T. Type name, T. So you still have a universal reference on the T. But just one constructor? Both, a copy and a move constructor. So they're not a copy and a move constructor if they don't take the exact type, right? So if you have a constructor that takes, for example in this class, if I had a constructor that takes an int, you wouldn't say that's a copy constructor or a move constructor. It's just yet another constructor. So if this thing was a template of whatever and you had a constructor taking whatever and not widget of whatever, that's not a copy and a move constructor. It's just yet another constructor. Yeah. Hopefully that clears things up. Okay. So we do have a few minutes left. So I want to show you real quick just one more example of using sort of the same techniques for a slightly different scenario for compile time computation. And first, I just want to make sure we're all familiar with constexpr. So basically in the good old days, to perform compile time computation, you'd have to do stuff like that with recursive templates. That's just a classical example. I'm sure you've all seen that thing. So for example, here I'm calculating factorial by having a class template specialization for size t where the base case is defined as one. And then all the other cases are recursively invoking that class template until it's specialized down to zero. So first of all, we can replace a lot of these recursive templates with constexpr, which was introduced in C++11. So when applied to a function, constexpr means that in some cases, the value that this function returns can be obtained at compile time. So you don't have to actually invoke it at runtime. You can just sort of run through that function at compile time and get the output. So here's factorial as just a constexpr function. And obviously, the advantage here is that even though the thing is calculated at compile time, you still specify it exactly the same way as any other function that would be calculated at runtime. Furthermore, you could use that factorial function with values that are known at compile time, and then the result is known at compile time, or with values that would only be known at runtime, and then the result would only be known at runtime, which is nice. In C++14, a lot of restrictions on constexpr were lifted. So for example, now in constexpr functions, you can use loops, and you can declare local variables, which you couldn't in C++11, where the whole thing had to be a single return expression. So that opens the door for a bunch of additional things that you can express as compile time computation. And you can even now have types which are constexpr essentially. So here's, for example, the complex type. Tuple has similar situations. So here's a complex type where the constructor can be constexpr, and it has a real and a set real function, which are constexpr, and the conjugate function that can be constexpr. So basically, we can now express computations on complex numbers, and they will be performed at compile time, which is rather cool. I think what's even more cool is that const and constexpr are two totally distinct concepts, right? So for example, here's a function, which is constexpr, but it's not const. It's actually mutating an object. That mutation just happens at compile time. So that's what we're saying by using constexpr here. This function here, it's mutating a value, but it's happening at compile time, so that's what constexpr means. Great. So here's the very, very quick overview of constexpr. Some simple uses are rather nice. So for example, you can replace the horrible array size macro, which takes an array, a statically defined array, and returns the number of elements in that array. You can replace that with a constexpr function template, which is where the template arguments are the type and the number of elements in the array, and we just return the number of elements. And that array size can be used at compile time situations. So for example, you could declare an array whose size is array size of some other array, which is a rather common use of array size. So that's a compile time known value. Another example is the power function, which can be calculated recursively. So 2 to the power of something comes up a lot. So these are simple uses, and there's a bunch of them in the library and in code you'd write yourself. But here's a slightly less obvious use, where constexpr can actually replace a bunch of class templates, which you would use to define meta functions before. So our task here, in this particular case, is to build a compile time facility, a compile time function, basically a meta function, which takes a certain type trait, a Boolean property of types, such as is integral or is floating point or is no throw move constructible, some kind of Boolean property of types, and an open collection of types, just any types we want, t1, t2, t3, an arbitrary number of types. And we want this thing here, and f, to evaluate whether this Boolean meta function is true for all my types, t1, t2, t3, and return true or false, which would be known at compile time. So this is a classic scenario, which you would solve using class template specialization before constexpr was available. You'd have to build a couple of class templates recursively. They would have to derive or extend each other. Here's the constexpr solution, which for me anyway, in some cases, is clearer. So here's the base case for endf for this little function. The base case doesn't take any types. It only takes the operator. It only takes the binary function, the Boolean function, such as is integral. And it returns true, because if you apply that function to no types, then we could say it is true for all the types, for all the no types we have. And then the interesting case, the recursive case is over here, where we have that operation, the Boolean property of types. We have the first type, and we have all the rest of the types, and the rest can also be empty, so we could be down to just one thing. And we just perform a recursive invocation, right? So we ask, is op of t true? And the recursive invocation for all the rest of the types is a true as well. And that's what we return. And the whole thing, of course, is constexpr, so it's all evaluated at compile time. It's not like at runtime you're actually going to have any recursive invocations. That whole thing just folds down to true or false at compile time. And for me, in some cases, this constexpr function style is more readable and more understandable than class templates, which would have to interact with each other through specializations, especially if the thing you're working with is values and not types. So in this case, I'm working with values. I have true, false, which I have to combine in some way, and not types, which would be harder to combine using just functions. So my final example from the constexpr area is one I've come across about a year ago, maybe a little more, which is parsing strings at compile time. So here's a little class called cstr for compile time string, which has a constructor from an array of characters with a known size. So it can basically be initialized from literal strings, right? literal strings known at compile time. So that's an array of characters, and the size is also known. What this constructor does is just initialize members, the pointer to the beginning of the string, and the length of the string. And now I can have, in that class, multiple constexpr operations which interact with these fields. So for example, I could do length function, which would return length. I can do an isEmpty function, which returns whether length is 0. I could also do a function which looks for a certain character in the string and returns the first occurrence. And that function would still be constexpr because this whole thing is performed at compile time. And one example of using it is for printf-like situations where I want to test that my format string is valid. So just think about it, if the format string is a compile time literal string, which happens in a lot of cases, you can validate it at compile time, not waiting until run time to make sure the format string is valid. So in this very simple example, I have a static assertion which makes sure that the count of percent signs in my format string is the same as the number of arguments passed to the printf function. So that's obviously a simplification because in printf format strings, you can have double percent sign and that's not a placeholder. But the general idea still holds. We can test at compile time whether a certain string literal has a certain number of percent signs and reject at compile time that format string if it doesn't. So for example, if I invoke my printf function with two arguments but only one percent sign, the compiler could complain and that static assertion would fire and tell me number of arguments doesn't match the format string. So obviously this is just a prototype, right? But it can be used in a lot of situations where I have to validate strings at compile time. For example, imagine a regular expression constructor that tests that the regular expression is well formed, a bunch of things that are quite easy to express once we have constexpr because you can essentially reuse the same code, the same algorithm for testing things at compile time and at runtime. So that's just a wrapper case for my examples. Right, so we have about three minutes left so if you have any questions, there will be a little time I hope. I hope you've seen some examples of using template metaprogramming in a variety of tasks in both libraries and applications. So admittedly, a lot of these examples are from the library world, implementing STL algorithms, optimizing them and so on. But hopefully application level examples can also be extracted from these samples. And with the tools we have in C++ today such as DecalType, such as constexpr, it's a lot easier to build these kind of solutions than it was in C++ 98. Now if you're seriously considering investing in TMP libraries, instead of building these basic tools yourself, there's a bunch of options to choose from, right? So you don't have to build the basic combinators, for example, for testing whether a certain property holds for multiple types, that kind of thing. You don't have to build yourself unless you just enjoy the process. I enjoy the process, but still you don't have to build these things yourself. There's a bunch of libraries including in Bust, some modern, some older, which provide solutions to common tasks that you have to perform at compile time. So this is all quite fun and hopefully will be applicable to at least some situations you encounter. And if you have any questions, we have about three minutes. Yeah. Yes. Why would you use such a station for the helpers? Instead of? Instead of the training type. Instead of? The extra pyramid. Okay, so just to repeat the question, why did I show you an example of using class template specialization and tag dispatch instead of just using one of them? So first, it's nice to see multiple options. And second, tag dispatch is usually used when you're trying to invoke a function. If you have a whole class template that you want to pick and that class template would have members and would have behavior, so state and you have multiple functions to invoke, I think it would be more convenient to use specialization. I think it's also a matter of taste to some extent. All right. Well anyway, thank you very, very much for coming and I'll have some samples for you on Twitter later if you'd like to explore some labs yourself and the examples I've shown you here today. I hope you enjoyed the rest of NDC. Thank you very, very much for coming. Thank you. Thank you.
 So basically building contracts for your APIs, making sure certain properties of types are  met before your API is invoked and can do stuff at runtime.  The other thing is member detection.  So basically building your own type checkers, which verify that certain types have certain  properties, have certain members, have certain subtypes.  Then we have algorithm selection.  So basically we'll specialize a certain algorithm, such as an STL algorithm or one of our own,  based on the type properties that we detect.  So there's a bunch of examples, and I'll show you a couple.  And finally, towards the end, there's a couple of examples of compile time computation with  constexpr, which really allows for a lot simpler type checking and a lot simpler computation  where you'd have to use recursive templates and a bunch of complex stuff before.  I'm going to just be using a lot of examples, and most of the stuff I'm doing here requires  C++11.  It should work with any C++11 conformant compiler, maybe except for Visual C++, which still has  some incompatibilities.  Some of the code requires C++14, but it can be rewritten to only require 11.  And without some features such as decal type, which were introduced in C++11, it's quite  hard or anyway harder to implement some of the things I'm going to talk about, and some  are even impossible, actually, with the older version of the standard.  So some motivation and examples.  Here's an example of a situation where constrained checking could actually be useful.  So if you're sitting in the back, you can't even read this whole thing.  But this is basically what happened when I just launched Xcode, built a little C++ project,  and tried to use as a map key a type that doesn't have the less than operator.  So I built an STD map, and the key is a type that doesn't have the less than operator.  Now just declaring a map like that, as you probably know, doesn't cause any issues in  compilation time.  However, trying to use it, so once I try and insert an element into the map with a certain  key, that blows up.  And this is just a very small part of the actual compiler error message that I received.  But one thing to note is that the error is coming from Clang in this case.  It's pretty decent, so it's telling me invalid operands to binary expression less than, where  I am trying to invoke less than on values of type const foo, and foo is the key type  in my map, which doesn't have the less than operator.  But then if you look at some of the further notes emitted by the compiler, there's a bunch  of nonsense here.  So why do I care about something called a tree with a value compare, and if you look a little  lower, it has some ridiculous stuff about not being able to match the operator less  than for pairs of whatever.  So if you're an experience C++ developer, you've seen this error before, and you know  that you just forgot to declare less than operator, so your keys are invalid.  But for less seasoned developers, this is very troubling.  And they can spend a while just posting this thing to stack overflow and getting flamed  by everyone.  So better error checking, for example, in the STL could be really helpful if at compile  time we could get a nice error message that says, well, in addition to all these other  problems, it is likely that what you forgot to do is just to declare less than or specialize  STD less for your type and just move forward.  So the other example I've mentioned is algorithm selection, where you have multiple versions  of an algorithm that can be more performant, more efficient for certain types.  Here's a couple of classic examples from the STL, which a lot of STL implementations actually  use.  So STD copy can be specialized if the thing we are copying is a plain old data type, doesn't  have any sophisticated assignment behavior, and you're copying from pointer ranges, not  iterators.  So if you basically have a mem copy situation and you are allowed to just optimize and use  mem copy instead of the slower loop version of STD copy, that can be a considerable performance  gains for certain types.  Another example is STD distance, and distance, as you know, finds the number of elements  in a range between two iterators.  So for certain iterators, such as random access iterators, it can be implemented in constant  time, O of 1, right?  And for, say, forward only iterators, you'd have to actually traverse the iterator so  you'd have an O of n, a linear time implementation.  So that's another example of where figuring out some information about the type could help  optimize an algorithm, select the right algorithm at compile time.  And then another example, as I said, is compile time computation.  So certain things can be pre-computed at compile time or solved entirely at compile time.  One example that I really hope to show you towards the end is string validation.  So if the user provides a literal string as an input to a certain function, we could check  that that string has certain properties at compile time instead of throwing an exception  at runtime.  And for certain APIs, such as maybe printf, right, it can be useful to emit errors as  early as possible at compile time instead of deferring to runtime.  So there's a bunch of users which hopefully illustrate this is a practical thing to talk  about, even though not the most practical in the world.  The main tool we'll be using throughout this talk is template specialization.  So this is just a very, very quick reminder of how this works, what it looks like.  So basically here we have a partial and an explicit complete specialization of the less  template.  So less has an operator that can be invoked as a function, and it compares two objects,  determines which one should be sorted before the other.  We also have a specialization for pointers here, which compares not the pointers, but  compares the targets, right, the pointees, the things the pointers are pointing to.  And finally we have a complete explicit specialization for a char pointer where we use strCmp.  So we're not comparing the char's, we're not comparing the pointers either, we are comparing  the whole string until the null terminator.  So that's just the tool we're going to be using, and hopefully you're all familiar with  that, but it never hurts to just see a quick example.  So let's start with constraint checking.  As you probably know, in the standard library there's a header type traits, which has a  bunch of useful meta functions which take types and return in some cases values, in  some cases types.  Meta functions basically operate at compile time on types and produce either values like  Booleans, for example, does a type have a certain property, or other types.  So for example, you could have a meta function that takes a type and adds a reference to  it.  So it produces the same type, but with a reference added at the end, or removes const from a  type, that kind of thing.  A lot of these can actually be implemented pretty easily, so if you're looking for exercises  on meta functions, you can implement a lot of these type traits yourself.  There's a lot of corner cases to take care of, but you could.  A lot of these, however, cannot be implemented without actual compiler support.  So the standard library implementation on a particular platform would have to ask the  compiler for hooks, which implement some of these type traits, because there's no way  to express in the language itself checking for that kind of constraint.  So some useful examples.  Is pointer, for example, checks if a type is a pointer type.  And it sounds easy, but if you actually look at the implementation, you have to take care  of pointers to functions and pointers to members, and const pointers, and pointers to const,  and a bunch of other edge cases.  So it's useful to have this in the library.  We have more complex traits such as is no throw copy constructable, right?  So does the type T have a copy constructor which is marked no accept, and will not emit  exceptions at runtime?  We can use a lot of these, and we can develop some of our own type traits based on what's  available in the library, and based on other techniques as well.  So here's a very simple example of using a type trait.  This is not a standard library situation, it's just a type I figured I want to develop.  It's a class called array.  There's actually std array in the standard library, but suppose that's not what we're  seeing here.  And my array wants to be a no throw kind of type, a no accept type.  I want the constructor of the array to not throw exceptions.  I want all the members actually to do the same.  And so if in my array I have a statically allocated array of Ts, I would like to produce  a clean error message in case that type T does not have a non-throwing default constructor.  So I can mark my own class's constructor as no accept, and that will produce some error  message if T doesn't meet the necessary requirements, but I actually want to go further than that,  and I want a clean assertion that says exactly what happened if the user uses an incorrect  type.  So I can put a static assertion that uses a standard library type trait and checks explicitly  that T has a default constructor, a parameter less constructor, which does not throw, which  is marked no accept explicitly.  Another example of using traits in a situation that's not exactly error checking, but rather  sort of making sure your implementation is very accurate, is this example from swap over  here.  So this is STD swap pretty much with some minor changes introduced.  Everyone's familiar with STD swap.  And what it does inside is it tries to use move operations, right?  In case the type T supports move, I wouldn't like to copy to a temporary and then copy  back from the temporary, I'd rather just do moves all the way.  And I would like the swap operator to be marked no accept.  I would like it, but I'm not actually sure if the code inside is going to be throwing  exceptions or not.  I don't know in advance whether, for example, the move constructor and the move assignment  operator for T are marked no accept or not.  So I don't want to emit an error in that case.  I don't want to place a static assert in my swap that says no.  You can't use this swap function if your T is not no accept because that just is plain  bad.  Instead, we could, in this case, for example, use the conditional form of the no accept operator.  So we could say that, OK, this function is no accept in case certain properties are met.  So this is the no accept operator which takes a Boolean value that has to be known at compile  time.  So my swap is no accept as long as T has no throw and no accept move constructor and a  no accept move assignment operator.  If these two properties hold, then the code I wrote is actually going to be no accept  correct.  So that's just another use of constraint checking and type checking that we could introduce,  even if not to emit errors, but just to make sure we're really expressing ourselves very  accurately.  OK, so suppose we have the basic type traits figured out, the ones that are in the standard  library, but we have a unique situation of our own.  We have some kind of property of a type that we want to detect, that we want to test for.  One example that I often use in training workshops is determining whether a certain type is an  STL container.  So for example, imagine you're building a serialization framework or maybe just a debug  printing framework that takes an arbitrary object and wants to print it as accurately  as possible.  So if the type already has an output operator, then I'll just invoke that.  If the type is a container, I would like to detect it's a container and print out the  contents, print out the elements of the container and do so recursively.  So this can be useful for serialization, can be useful for, again, debug printouts, but  the question is how is this generic template print function or serialized function is going  to figure out if our type is a container or not.  We'll have to have multiple implementations and pick the right one, but in order to pick,  we have to ask, is this thing a container?  So we could go with the formal definitions of what a container is or maybe a range if  we want to work with somewhat newer concepts, but still it boils down to asking, does a type  have certain properties?  So for example, to be very naive, I could say a type is a container if it has a begin  member function.  So a bunch of types might have a begin member functions and not be containers and also arrays  are containers but they don't have a member function called begin, but that would be an  approximation.  Or I could maybe say a type is a container if it has an nested type def called iterator,  right, like vector, iterator, map, iterator and so on.  So again, that wouldn't work for arrays, but it would be an approximation.  And if we wanted to be super accurate, we could just ask, what do we want to do with  that object if it is a container?  So the answer is, okay, if it is a container, I want to enumerate all the elements in the  container and then I could just test for that directly.  So can I invoke begin and get something that looks like an iterator which I can increment  and compare and dereference?  So there's a bunch of type properties that we want to be checking.  So this happens a lot, again, if you're building generic libraries that have to ask for, that  have to care about the properties of the given type, sometimes just to reject certain types  and in other cases to specialize your decision based on properties of a type.  So let's build something that detects whether a type is a container.  There's a bunch of techniques for this.  Even in C++98, we could sort of ask if a type has certain members, for example, or if a  type has certain nested type defs, but in C++11 with decal type and with a bunch of further  advances, we have easier solutions for this problem.  So again, we want to build our own type traits which ask, does a type have a certain member  or more generally, does a certain expression make sense for my type?  Does it compile?  And even maybe does it produce a certain type as a result?  So for example, not just, for example, for the dereference operator on iterators, I actually  wanted to produce a value.  If I have a void returning dereference operator, that's a little fishy for a container.  So we want to ask if a certain expression makes sense and maybe produces a particular  type.  So there's a very cool trick here introduced by Walter Brown, I think a couple of years  ago at CPPCon, I was very impressed when I saw it first.  There's a bunch of other ways to express the same thing, but this one is so clean and so  concise that I really fell in love with this technique and I've been telling about it to  people since.  So basically, you have this super simple and weird looking template.  This is actually a Lalias template which defines void t as void for any type.  So this is a template, you could say void t of int, void t of float, void t of std vector,  and it's always just void.  It's always defined to be void.  The point is not that it is void.  The point is that if we try and use this thing, if we try and use void t with a type that's  not well formed, with a type that's not valid, then this thing just has no definition.  The thing doesn't make sense.  So void t wouldn't be sensible, whereas if we use any valid type as the template parameter  here, we would get void always, just regardless of what we put in.  There's alternatives for this in the standard library, but it's really clean to just see  it this way.  So here's how we use it for isContainer in our example.  Up top, there's the first version, the more general version of the isContainer template,  and it has two template type parameters, t and another one, which is unnamed, I don't  care what it's called, and it has a default type parameter value which is void.  So this one is the more generic template, it's not a specialization, and this one is  defined to inherit from std is array of t.  So basically, if we go to that isContainer template up top and we ignore everything else  on the slide, then it's basically equivalent to asking is t an array.  If t is an array, then this template recognizes it as a container, and if t is not an array,  then we don't recognize it as a container.  So we've taken care of arrays separately.  And isArray, of course, is defined in type traits, and we assume it works correctly.  And then we have the specialization.  It's occasionally unclear why this thing is even a specialization of the first thing.  So how would you convince your friends that this second definition is a specialization  of the first?  It has fewer type parameters.  It has fewer type parameters, right?  So the one up top has two type parameters, even though the second one has a default value,  but the one on the bottom only has one type parameter.  So that's enough for me, I suppose.  And this is container template is a specialization in case, well, t, the first argument is just  the t we got passed in.  And the second thing, the second type parameter, which has a default value of void over here,  the second type parameter is that void t template specialized, well, sorry, parameterized with  t iterator, right, with the nested iterator type def.  And if we use this specialization, then I just inherit from a true type to indicate  that yes, we are a container.  So basically, if this specialization is chosen, then we deduced that t is a container.  Okay, so for this specialization to be chosen, what needs to happen is that void t of that  type is well-formed.  If it is not, if our type is, for example, an int, then what we have over here is just  int column, column, iterator.  That doesn't make sense.  That's not well-formed.  And then substitution failure kicks in, and we just ignore this specialization.  And we have our base case, which will then deduce that int, because it's not an array,  is not a container.  But if t does have a nested iterator type def, then this thing over here is well-formed,  and this is just plain void, right?  And then this is a specialization of the previous case, and this specialization is a better  match, so the compiler, when doing the template specialization pattern matching, would pick  this version and deduce that our type is a container because we inherited from true type.  Why, just one final thing, why does it matter that this here is void?  Why did they put void in here and not something else?  I was looking for the same person to answer.  Yeah, no, so what I'm asking is why does this have to be void and not say int, right?  Because this has to be void, and the thing that happens is if the user of my template  of isContainer doesn't provide the second type, right, so my user says isContainerOfInt.  The user doesn't specify what the second type is, so if the user says isContainerOfInt,  I would like both versions to be potential candidates.  So in this case, isContainer, the first version, would be isContainerOfT and void, and this  one would be isContainerOfT and whatever void T produces.  So if void T produces void, we have our two candidates, and the more specialized one can  be picked.  But if here, I said int, for example, then when the user says isContainerOfWhatever,  then what the user actually said is isContainerWhatever,int, right, and then the second specialization  would just never be valid because void T doesn't produce an int, it produces void.  So all the parts here matter, right?  It does matter that we have void up there, it matters that void T returns void.  Everything's important in this skeleton, if you will, for member detection.  Now you might ask, can this be generalized further?  And yes, it can.  So here, we're just testing if a type has a certain nested type def, but we can make  this further generic, if you will.  So if I want to test that a certain expression, arbitrary expression pretty much on arbitrary  types makes sense, and that's the trait I am checking for, that's the property I'm  testing for, then the general recipe would be.  We define an alias template for that specific test, and it's basically just the decal type  of whatever this expression returns.  So suppose I want to check if T1 has a member function called foo, which takes a T2, right?  So I have this alias template, which is a template in T1 and T2, and it is declared as the decal  type of this expression here, which declares a value of type T1 reference, and then invokes  foo on it, passing in a T2, right?  And the decal val function is just a very stupid silly little function from the standard  library.  It has no body, it's just a declaration, because we use it in context which do not require  evaluation.  So it's basically just declaring T1 for us or T2 for us.  That's the only thing we care about.  Once we have that test, we just plug it into our skeleton.  So the generic version of does my condition, is my condition true for a certain pair of  types, the one over here, the generic version, takes T1 and T2 and that dummy void template  parameter, and the specialization takes T1 and T2 and whatever void T returns when invoked  with my test, which is up there.  So if that expression makes sense, if this thing here is well formed, then void T produces  void and we pick the second specialization, and if it is not well formed, then we pick  the first one and we reject that property.  And we could even test if we wanted that my test T is not just well formed, we could ask  what kind of thing it is.  So I could add, for example over here, I could add, so is my test T of T1 and T2 actually  say an int or a const reference or whatever else I wanted to assert?  So we basically have now a generic recipe for checking properties of types thanks to this  void T trick.  This again, it requires compiler support.  So for example, my usual go to compiler again, which is Visual C++, still has some restrictions  around expression substitution failure is not an error, expression is finite, so it would  actually reject a bunch of these examples.  But the more conforming compilers, GCC, Clang, they're okay with this.  And Microsoft is working on fixing the edge cases that still don't work.  And actually this kind of template is pretty useful in the standard library as well.  So just as an example, in the standard library, there is a type trait called is assignable,  which just determines whether one type can be assigned to another using the assignment  operator.  You could easily implement it using this generic trick, right?  So over here in the decal type body, we would have just decal val A assignment, decal val  B, and we'd have to test if that is well formed.  So standard libraries all over the world can now use this instead of requiring compiler  hooks or some sophisticated one-off tricks.  There's just a generic trick that works for all the cases.  So that was member detection.  And once we have that, let's talk about some ways, right, some strategies for actually  using the property we discovered for choosing one of multiple algorithms.  Again if we want to optimize STD copy, for example, for pointers to primitive types as  opposed to the general case of just iterators we know nothing about.  So there's three general strategies I want to show you, which are common in a bunch of  different template libraries, including the STL.  One is just explicit specialization when you write all the boilerplate yourself.  The other is tag dispatch, which is useful and used a lot in the STL, where you have  multiple versions of an algorithm.  So basically the property you're testing is not binary, true or false.  It has multiple degrees of being true.  And there's also STD enable if, which is usually used if you want to disable a certain function,  if you want to remove a certain function from the set of overloads that you would want the  compiler to consider.  So let's take a look at a few examples.  Again, just an overview of the tricks that a lot of libraries use.  So this rather verbose thing on the screen is an attempt to specialize the sort implementation,  just a general sort that takes iterators for two cases.  One when the type we're sorting just has general properties, is generally comparable, right?  So it has a less than operator, which provides order.  And the other case is if it's hashable, if there is a way to produce hashes from values  of that type.  So if it is hashable, maybe I'm going to use a different sort algorithm like radix sort,  and if it's not hashable, I'm going to use something else.  It's just an example.  I'm not saying there's a practical use of this kind of sort implementation.  But we want to ask about the property of the type and then just redirect to two different  implementations.  So I can have this base case of a sort imple class template, which is undefined.  Basically I don't care about it because I am going to have specializations for both  of the cases.  So this base template is a template of some type and the Boolean.  And then I have two specializations.  I have one for some type and false, and another for some type and true.  So I basically covered all the cases because Booleans can be either true or false.  So there shouldn't be any case where we actually get to the base template and the compiler  would complain that we haven't actually defined it.  So for false, I have one definition of a static sort function, and for true, I have  a different definition of a static sort function.  So basically this is just a way of picking overloads at compile time.  I have two functions in two different class templates, and I'm choosing the right one  based on whether some property is true or false at compile time.  So now I just have to ask, is that property true?  And redirect to one of the options.  So in this version, which is the publicly accessible one, that's the thing that clients  actually invoke.  In this version, I specialize sort-imple, I parameterize sort-imple by whether the value  type of that iterator has some property.  So is hashable v?  That's not a standard library thing, but it's a type trait that we built using the techniques  we talked about previously.  So sort-imple of my iterator type, and either true or false, just picks one of the two class  template specializations we had over here, and then I invoke the static sort method on  that passing in my iterators.  So we have just successfully picked one of two implementations based on a Boolean property  of some type.  This is a bit verbose, but it works, and in some cases, you might actually prefer it.  For example, if that type that you're using actually has to have some state and member  functions, it's actually useful to just pick one of multiple class template specializations  and then just work with that class template, kind of like the strategy pattern, except  you're doing it in compile time and not at runtime.  And this can be obviously expanded further to a bunch of additional examples.  The other alternative, which is pretty common in the standard library, is tag dispatch.  This doesn't require class template specialization, just multiple overloads of a certain function,  and the overloads are different only by usually a trailing type which can take multiple type  values.  So here's a classic example from distance.  This is an STD algorithm that finds the distance between two iterators, right?  How many elements are in the range between two iterators?  So this is the publicly accessible declaration.  So distance takes two iterators.  What it returns is, well, whatever iterator traits difference type is for my iterator  type.  So conveniently, we have iterator traits, which is supposed to tell us things about  iterators.  This is yet another example of a meta function that takes types and returns values and types  for us.  And then I invoke distance helper, which is not a publicly accessible interface, and  distance helper takes the two iterators first and last, as well as an additional parameter.  And this one is also obtained from iterator traits.  So in iterator traits, I have iterator category, which is a type.  So I instantiate that type over here, and that's what I pass to distance helper.  So now distance helper can be overloaded for various types that iterator category can  return.  Just for simplicity, suppose iterator category is sometimes an int and sometimes a float.  So I can now build two distance helpers, one that takes an int and one that takes a float  as the third parameter, and in such a way specialize my implementation.  Iterator category, fortunately, doesn't return int or float.  It's a meta function that returns one of multiple types, indicating what kind of iterators we  have on our hands.  So it could be forward iterator, an input iterator, bidirectional iterator, random access iterator,  and so on.  And here's what the actual helper could look like.  So for random access iterator tag, which is the iterator category for random access  iterators, my implementation just uses the minus operator, right?  So we just find the distance between the two iterators.  And for anything else, this is the second version of distance helper, it takes iterator  tag base, which is the base class of all the other iterator categories, of all the iterator  categories.  So for iterator tag base, we have the implementation here, which declares a counter and then just  traverses the range, incrementing the counter till we reach last, right?  So while first is not last, increment last, increment n till we get to the end and then  return n.  So this is going to be the linear time version, and that's going to be, hopefully, a constant  time version.  And we just used a property, a type property, returned by iterator category to choose one  of the two.  So that's a pretty common technique as well.  And a third example I want to show you is an A...  Just like a lot of classes.  And it also has this constructor over here, which takes a universal reference to any  t.  And the reason you'd usually have that kind of constructor, does it work now?  Okay.  So the reason you'd usually have that kind of constructor, which takes a universal reference,  is not to emulate a copy constructor and a move constructor on your own type, but rather  to enable construction from some other type.  So for example, maybe my widget, it can actually be constructed from, for example, a tuple  of configuration values.  And I want to optimize for two cases, one when I am passed an r-value reference, which  I can move from, and the other when I'm passed a const reference to an l-value, which I  can only copy from.  That's a pretty common situation.  But even ignore the reason why I actually have that kind of templated constructor.  The issue here is hiding.  What can happen is that if the user of my widget class initializes a widget and uses an l-value  reference to a widget, which is not const, so basically just widget ampersand, right,  an l-value reference to a widget which isn't const, then the compiler can choose between  my copy constructor, which takes a const reference to a widget, and this template constructor,  which was never intended for situations where t is a widget, but it would apply in that  case, and it would be picked, because this constructor works where the t ref ref actually  resolves to just a widget ampersand, to an l-value reference to a widget.  So we have a constructor that takes a const reference and a constructor which takes a non-const  reference, and that second constructor would be preferred.  So essentially, we built a universal constructor which hides our own copy constructor.  This is undesirable.  So we can ask the compiler, essentially, to not pick that specific overload, that specific  constructor, if I'm using a widget as t.  So the way this typically works is that somewhere in the signature, and there's a lot of places  you could actually put that in the signature, somewhere in the signature, you put enable  if, and enable if is very similar to void t, actually.  It just determines whether an expression is well-formed, and then it's used for substitution  failure to remove that overload from the set of overloads that can be considered.  So in this case, the expression I'm passing to enable if is not is same t widget reference  value.  So basically a Boolean which says whether or not t is the same thing as an l-value reference  to a widget.  So if t is the same thing as an l-value reference to a widget, this expression, because of the  not here, this expression is going to be false.  And then we have enable if of false, and enable if of false is not defined.  So it's not a type, it's not any type, whereas enable if of true is void, kind of like our  void t template.  So in the case where enable if t here produces void, this template overload is considered  valid, and in the case where enable if t takes false, and it is undefined, this constructor  is just removed from the set of candidates because it is a substitution failure when  trying to match the template arguments, the template type arguments.  You could place that enable if in a bunch of additional places, maybe in, when reviewing  template libraries, you might have seen enable if as an additional parameter, right?  So in some cases you put it as an additional parameter which has a default null value.  You could use enable if as the return type, not in a constructor though, constructors  can't have declared return types, but in other functions you could use enable if t is the  return type, again just to get the compiler to consider that type as part of the function's  signature.  Again if it doesn't match, then this signature, that overload is removed from the set of candidates  that the compiler would consider.  So in this way we could just disable this overload in certain circumstances, and this  trick is used a lot in the STL, yeah?  Is there a way to apply this trick if it's not in some kind of place?  Is there a way to apply it?  Without the constructor constructors?  What do you mean?  If you have templates like the NT of rigid and you have a copy constructor and a move  constructor, and you wanted it to choose the copy constructor in the cases where it was  actually copying instead of moving.  As you said, the move constructor will always be preferred if it's a long const.  So if you declare a copy constructor and the move constructor, then the move constructor  will be chosen if you have an r-value reference, if you have a reference to a temporary, if  you have a reference to an l-value, then the copy constructor will always be chosen  automatically.  Just think about it, your move constructor is going to be moving, so it's going to destroy  the object.  If you have an l-value, that would be extremely unsafe.  You don't need this trick at all if you just declare a copy constructor and a move constructor  and you want the compiler to pick.  So in that case it doesn't actually collapse to its own reference?  It was not?  It didn't collapse to just a reference in that case?  So you're saying no template here, no universal reference, just a copy constructor and a move  constructor, right?  No, I'm saying that the class is template.  Oh, that's fine.  And the constructors, what do they take?  Do they take widgets or do they take one of the template arguments?  Type name, T.  Type name, T.  So you still have a universal reference on the T.  But just one constructor?  Both, a copy and a move constructor.  So they're not a copy and a move constructor if they don't take the exact type, right?  So if you have a constructor that takes, for example in this class, if I had a constructor  that takes an int, you wouldn't say that's a copy constructor or a move constructor.  It's just yet another constructor.  So if this thing was a template of whatever and you had a constructor taking whatever and  not widget of whatever, that's not a copy and a move constructor.  It's just yet another constructor.  Yeah.  Hopefully that clears things up.  Okay.  So we do have a few minutes left.  So I want to show you real quick just one more example of using sort of the same techniques  for a slightly different scenario for compile time computation.  And first, I just want to make sure we're all familiar with constexpr.  So basically in the good old days, to perform compile time computation, you'd have to do  stuff like that with recursive templates.  That's just a classical example.  I'm sure you've all seen that thing.  So for example, here I'm calculating factorial by having a class template specialization  for size t where the base case is defined as one.  And then all the other cases are recursively invoking that class template until it's specialized  down to zero.  So first of all, we can replace a lot of these recursive templates with constexpr, which  was introduced in C++11.  So when applied to a function, constexpr means that in some cases, the value that this function  returns can be obtained at compile time.  So you don't have to actually invoke it at runtime.  You can just sort of run through that function at compile time and get the output.  So here's factorial as just a constexpr function.  And obviously, the advantage here is that even though the thing is calculated at compile  time, you still specify it exactly the same way as any other function that would be calculated  at runtime.  Furthermore, you could use that factorial function with values that are known at compile  time, and then the result is known at compile time, or with values that would only be known  at runtime, and then the result would only be known at runtime, which is nice.  In C++14, a lot of restrictions on constexpr were lifted.  So for example, now in constexpr functions, you can use loops, and you can declare local  variables, which you couldn't in C++11, where the whole thing had to be a single return  expression.  So that opens the door for a bunch of additional things that you can express as compile time  computation.  And you can even now have types which are constexpr essentially.  So here's, for example, the complex type.  Tuple has similar situations.  So here's a complex type where the constructor can be constexpr, and it has a real and a  set real function, which are constexpr, and the conjugate function that can be constexpr.  So basically, we can now express computations on complex numbers, and they will be performed  at compile time, which is rather cool.  I think what's even more cool is that const and constexpr are two totally distinct concepts,  right?  So for example, here's a function, which is constexpr, but it's not const.  It's actually mutating an object.  That mutation just happens at compile time.  So that's what we're saying by using constexpr here.  This function here, it's mutating a value, but it's happening at compile time, so that's  what constexpr means.  Great.  So here's the very, very quick overview of constexpr.  Some simple uses are rather nice.  So for example, you can replace the horrible array size macro, which takes an array, a  statically defined array, and returns the number of elements in that array.  You can replace that with a constexpr function template, which is where the template arguments  are the type and the number of elements in the array, and we just return the number of  elements.  And that array size can be used at compile time situations.  So for example, you could declare an array whose size is array size of some other array,  which is a rather common use of array size.  So that's a compile time known value.  Another example is the power function, which can be calculated recursively.  So 2 to the power of something comes up a lot.  So these are simple uses, and there's a bunch of them in the library and in code you'd write  yourself.  But here's a slightly less obvious use, where constexpr can actually replace a bunch of  class templates, which you would use to define meta functions before.  So our task here, in this particular case, is to build a compile time facility, a compile  time function, basically a meta function, which takes a certain type trait, a Boolean  property of types, such as is integral or is floating point or is no throw move constructible,  some kind of Boolean property of types, and an open collection of types, just any types  we want, t1, t2, t3, an arbitrary number of types.  And we want this thing here, and f, to evaluate whether this Boolean meta function is true  for all my types, t1, t2, t3, and return true or false, which would be known at compile  time.  So this is a classic scenario, which you would solve using class template specialization  before constexpr was available.  You'd have to build a couple of class templates recursively.  They would have to derive or extend each other.  Here's the constexpr solution, which for me anyway, in some cases, is clearer.  So here's the base case for endf for this little function.  The base case doesn't take any types.  It only takes the operator.  It only takes the binary function, the Boolean function, such as is integral.  And it returns true, because if you apply that function to no types, then we could say it  is true for all the types, for all the no types we have.  And then the interesting case, the recursive case is over here, where we have that operation,  the Boolean property of types.  We have the first type, and we have all the rest of the types, and the rest can also be  empty, so we could be down to just one thing.  And we just perform a recursive invocation, right?  So we ask, is op of t true?  And the recursive invocation for all the rest of the types is a true as well.  And that's what we return.  And the whole thing, of course, is constexpr, so it's all evaluated at compile time.  It's not like at runtime you're actually going to have any recursive invocations.  That whole thing just folds down to true or false at compile time.  And for me, in some cases, this constexpr function style is more readable and more understandable  than class templates, which would have to interact with each other through specializations,  especially if the thing you're working with is values and not types.  So in this case, I'm working with values.  I have true, false, which I have to combine in some way, and not types, which would be  harder to combine using just functions.  So my final example from the constexpr area is one I've come across about a year ago,  maybe a little more, which is parsing strings at compile time.  So here's a little class called cstr for compile time string, which has a constructor from an  array of characters with a known size.  So it can basically be initialized from literal strings, right?  literal strings known at compile time.  So that's an array of characters, and the size is also known.  What this constructor does is just initialize members, the pointer to the beginning of the  string, and the length of the string.  And now I can have, in that class, multiple constexpr operations which interact with these  fields.  So for example, I could do length function, which would return length.  I can do an isEmpty function, which returns whether length is 0.  I could also do a function which looks for a certain character in the string and returns  the first occurrence.  And that function would still be constexpr because this whole thing is performed at compile  time.  And one example of using it is for printf-like situations where I want to test that my format  string is valid.  So just think about it, if the format string is a compile time literal string, which happens  in a lot of cases, you can validate it at compile time, not waiting until run time to  make sure the format string is valid.  So in this very simple example, I have a static assertion which makes sure that the count  of percent signs in my format string is the same as the number of arguments passed to  the printf function.  So that's obviously a simplification because in printf format strings, you can have double  percent sign and that's not a placeholder.  But the general idea still holds.  We can test at compile time whether a certain string literal has a certain number of percent  signs and reject at compile time that format string if it doesn't.  So for example, if I invoke my printf function with two arguments but only one percent sign,  the compiler could complain and that static assertion would fire and tell me number of  arguments doesn't match the format string.  So obviously this is just a prototype, right?  But it can be used in a lot of situations where I have to validate strings at compile  time.  For example, imagine a regular expression constructor that tests that the regular expression  is well formed, a bunch of things that are quite easy to express once we have constexpr  because you can essentially reuse the same code, the same algorithm for testing things  at compile time and at runtime.  So that's just a wrapper case for my examples.  Right, so we have about three minutes left so if you have any questions, there will be  a little time I hope.  I hope you've seen some examples of using template metaprogramming in a variety of tasks  in both libraries and applications.  So admittedly, a lot of these examples are from the library world, implementing STL algorithms,  optimizing them and so on.  But hopefully application level examples can also be extracted from these samples.  And with the tools we have in C++ today such as DecalType, such as constexpr, it's a lot  easier to build these kind of solutions than it was in C++ 98.  Now if you're seriously considering investing in TMP libraries, instead of building these  basic tools yourself, there's a bunch of options to choose from, right?  So you don't have to build the basic combinators, for example, for testing whether a certain  property holds for multiple types, that kind of thing.  You don't have to build yourself unless you just enjoy the process.  I enjoy the process, but still you don't have to build these things yourself.  There's a bunch of libraries including in Bust, some modern, some older, which provide solutions  to common tasks that you have to perform at compile time.  So this is all quite fun and hopefully will be applicable to at least some situations  you encounter.  And if you have any questions, we have about three minutes.  Yeah.  Yes.  Why would you use such a station for the helpers?  Instead of?  Instead of the training type.  Instead of?  The extra pyramid.  Okay, so just to repeat the question, why did I show you an example of using class template  specialization and tag dispatch instead of just using one of them?  So first, it's nice to see multiple options.  And second, tag dispatch is usually used when you're trying to invoke a function.  If you have a whole class template that you want to pick and that class template would  have members and would have behavior, so state and you have multiple functions to invoke,  I think it would be more convenient to use specialization.  I think it's also a matter of taste to some extent.  All right.  Well anyway, thank you very, very much for coming and I'll have some samples for you  on Twitter later if you'd like to explore some labs yourself and the examples I've shown  you here today.  I hope you enjoyed the rest of NDC.  Thank you very, very much for coming.  Thank you.  Thank you.
Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_0_59.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_60_107.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_108_359.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_360_407.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_408_467.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_468_731.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_732_1331.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_1332_1595.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_1596_2471.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_2472_2531.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_2532_3839.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_3840_3887.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_3888_4427.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_4428_4655.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_4656_4703.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_4704_4943.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_4944_5651.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_5652_5963.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_5964_6863.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_6864_7427.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_7428_7955.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_7956_8927.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_8928_10523.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_10524_10571.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_10572_13511.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_13512_15467.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_15468_17279.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_17280_18467.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_18468_23423.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_23424_24431.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_24432_26507.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_26508_28139.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_28140_35087.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_35088_40775.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_40776_41411.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_41412_42539.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_42540_43019.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_43020_43667.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_43668_44855.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_44856_46823.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_46824_47195.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_47196_47483.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_47484_47903.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_47904_51251.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_51252_52835.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_52836_53003.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_53004_53099.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_53100_54119.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_54120_54191.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_54192_54707.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_54708_54767.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_54768_57671.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_57672_65075.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_65076_65483.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_65484_66335.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_66336_67703.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_67704_69731.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_69732_71231.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_71232_72383.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_72384_74279.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_74280_74651.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_74652_75887.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_75888_77783.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_77784_78491.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_78492_80471.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_80472_82523.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_82524_84635.png Introduction_to_C_Template_Metaprogramming_-_Sasha_Goldshtein_84636_84784.png
So basically building contracts for your APIs, making sure certain properties of types are met before your API is invoked and can do stuff at runtime. The other thing is member detection. So basically building your own type checkers, which verify that certain types have certain properties, have certain members, have certain subtypes. Then we have algorithm selection. So basically we'll specialize a certain algorithm, such as an STL algorithm or one of our own, based on the type properties that we detect. So there's a bunch of examples, and I'll show you a couple. And finally, towards the end, there's a couple of examples of compile time computation with constexpr, which really allows for a lot simpler type checking and a lot simpler computation where you'd have to use recursive templates and a bunch of complex stuff before. I'm going to just be using a lot of examples, and most of the stuff I'm doing here requires C++11. It should work with any C++11 conformant compiler, maybe except for Visual C++, which still has some incompatibilities. Some of the code requires C++14, but it can be rewritten to only require 11. And without some features such as decal type, which were introduced in C++11, it's quite hard or anyway harder to implement some of the things I'm going to talk about, and some are even impossible, actually, with the older version of the standard. So some motivation and examples. Here's an example of a situation where constrained checking could actually be useful. So if you're sitting in the back, you can't even read this whole thing. But this is basically what happened when I just launched Xcode, built a little C++ project, and tried to use as a map key a type that doesn't have the less than operator. So I built an STD map, and the key is a type that doesn't have the less than operator. Now just declaring a map like that, as you probably know, doesn't cause any issues in compilation time. However, trying to use it, so once I try and insert an element into the map with a certain key, that blows up. And this is just a very small part of the actual compiler error message that I received. But one thing to note is that the error is coming from Clang in this case. It's pretty decent, so it's telling me invalid operands to binary expression less than, where I am trying to invoke less than on values of type const foo, and foo is the key type in my map, which doesn't have the less than operator. But then if you look at some of the further notes emitted by the compiler, there's a bunch of nonsense here. So why do I care about something called a tree with a value compare, and if you look a little lower, it has some ridiculous stuff about not being able to match the operator less than for pairs of whatever. So if you're an experience C++ developer, you've seen this error before, and you know that you just forgot to declare less than operator, so your keys are invalid. But for less seasoned developers, this is very troubling. And they can spend a while just posting this thing to stack overflow and getting flamed by everyone. So better error checking, for example, in the STL could be really helpful if at compile time we could get a nice error message that says, well, in addition to all these other problems, it is likely that what you forgot to do is just to declare less than or specialize STD less for your type and just move forward. So the other example I've mentioned is algorithm selection, where you have multiple versions of an algorithm that can be more performant, more efficient for certain types. Here's a couple of classic examples from the STL, which a lot of STL implementations actually use. So STD copy can be specialized if the thing we are copying is a plain old data type, doesn't have any sophisticated assignment behavior, and you're copying from pointer ranges, not iterators. So if you basically have a mem copy situation and you are allowed to just optimize and use mem copy instead of the slower loop version of STD copy, that can be a considerable performance gains for certain types. Another example is STD distance, and distance, as you know, finds the number of elements in a range between two iterators. So for certain iterators, such as random access iterators, it can be implemented in constant time, O of 1, right? And for, say, forward only iterators, you'd have to actually traverse the iterator so you'd have an O of n, a linear time implementation. So that's another example of where figuring out some information about the type could help optimize an algorithm, select the right algorithm at compile time. And then another example, as I said, is compile time computation. So certain things can be pre-computed at compile time or solved entirely at compile time. One example that I really hope to show you towards the end is string validation. So if the user provides a literal string as an input to a certain function, we could check that that string has certain properties at compile time instead of throwing an exception at runtime. And for certain APIs, such as maybe printf, right, it can be useful to emit errors as early as possible at compile time instead of deferring to runtime. So there's a bunch of users which hopefully illustrate this is a practical thing to talk about, even though not the most practical in the world. The main tool we'll be using throughout this talk is template specialization. So this is just a very, very quick reminder of how this works, what it looks like. So basically here we have a partial and an explicit complete specialization of the less template. So less has an operator that can be invoked as a function, and it compares two objects, determines which one should be sorted before the other. We also have a specialization for pointers here, which compares not the pointers, but compares the targets, right, the pointees, the things the pointers are pointing to. And finally we have a complete explicit specialization for a char pointer where we use strCmp. So we're not comparing the char's, we're not comparing the pointers either, we are comparing the whole string until the null terminator. So that's just the tool we're going to be using, and hopefully you're all familiar with that, but it never hurts to just see a quick example. So let's start with constraint checking. As you probably know, in the standard library there's a header type traits, which has a bunch of useful meta functions which take types and return in some cases values, in some cases types. Meta functions basically operate at compile time on types and produce either values like Booleans, for example, does a type have a certain property, or other types. So for example, you could have a meta function that takes a type and adds a reference to it. So it produces the same type, but with a reference added at the end, or removes const from a type, that kind of thing. A lot of these can actually be implemented pretty easily, so if you're looking for exercises on meta functions, you can implement a lot of these type traits yourself. There's a lot of corner cases to take care of, but you could. A lot of these, however, cannot be implemented without actual compiler support. So the standard library implementation on a particular platform would have to ask the compiler for hooks, which implement some of these type traits, because there's no way to express in the language itself checking for that kind of constraint. So some useful examples. Is pointer, for example, checks if a type is a pointer type. And it sounds easy, but if you actually look at the implementation, you have to take care of pointers to functions and pointers to members, and const pointers, and pointers to const, and a bunch of other edge cases. So it's useful to have this in the library. We have more complex traits such as is no throw copy constructable, right? So does the type T have a copy constructor which is marked no accept, and will not emit exceptions at runtime? We can use a lot of these, and we can develop some of our own type traits based on what's available in the library, and based on other techniques as well. So here's a very simple example of using a type trait. This is not a standard library situation, it's just a type I figured I want to develop. It's a class called array. There's actually std array in the standard library, but suppose that's not what we're seeing here. And my array wants to be a no throw kind of type, a no accept type. I want the constructor of the array to not throw exceptions. I want all the members actually to do the same. And so if in my array I have a statically allocated array of Ts, I would like to produce a clean error message in case that type T does not have a non-throwing default constructor. So I can mark my own class's constructor as no accept, and that will produce some error message if T doesn't meet the necessary requirements, but I actually want to go further than that, and I want a clean assertion that says exactly what happened if the user uses an incorrect type. So I can put a static assertion that uses a standard library type trait and checks explicitly that T has a default constructor, a parameter less constructor, which does not throw, which is marked no accept explicitly. Another example of using traits in a situation that's not exactly error checking, but rather sort of making sure your implementation is very accurate, is this example from swap over here. So this is STD swap pretty much with some minor changes introduced. Everyone's familiar with STD swap. And what it does inside is it tries to use move operations, right? In case the type T supports move, I wouldn't like to copy to a temporary and then copy back from the temporary, I'd rather just do moves all the way. And I would like the swap operator to be marked no accept. I would like it, but I'm not actually sure if the code inside is going to be throwing exceptions or not. I don't know in advance whether, for example, the move constructor and the move assignment operator for T are marked no accept or not. So I don't want to emit an error in that case. I don't want to place a static assert in my swap that says no. You can't use this swap function if your T is not no accept because that just is plain bad. Instead, we could, in this case, for example, use the conditional form of the no accept operator. So we could say that, OK, this function is no accept in case certain properties are met. So this is the no accept operator which takes a Boolean value that has to be known at compile time. So my swap is no accept as long as T has no throw and no accept move constructor and a no accept move assignment operator. If these two properties hold, then the code I wrote is actually going to be no accept correct. So that's just another use of constraint checking and type checking that we could introduce, even if not to emit errors, but just to make sure we're really expressing ourselves very accurately. OK, so suppose we have the basic type traits figured out, the ones that are in the standard library, but we have a unique situation of our own. We have some kind of property of a type that we want to detect, that we want to test for. One example that I often use in training workshops is determining whether a certain type is an STL container. So for example, imagine you're building a serialization framework or maybe just a debug printing framework that takes an arbitrary object and wants to print it as accurately as possible. So if the type already has an output operator, then I'll just invoke that. If the type is a container, I would like to detect it's a container and print out the contents, print out the elements of the container and do so recursively. So this can be useful for serialization, can be useful for, again, debug printouts, but the question is how is this generic template print function or serialized function is going to figure out if our type is a container or not. We'll have to have multiple implementations and pick the right one, but in order to pick, we have to ask, is this thing a container? So we could go with the formal definitions of what a container is or maybe a range if we want to work with somewhat newer concepts, but still it boils down to asking, does a type have certain properties? So for example, to be very naive, I could say a type is a container if it has a begin member function. So a bunch of types might have a begin member functions and not be containers and also arrays are containers but they don't have a member function called begin, but that would be an approximation. Or I could maybe say a type is a container if it has an nested type def called iterator, right, like vector, iterator, map, iterator and so on. So again, that wouldn't work for arrays, but it would be an approximation. And if we wanted to be super accurate, we could just ask, what do we want to do with that object if it is a container? So the answer is, okay, if it is a container, I want to enumerate all the elements in the container and then I could just test for that directly. So can I invoke begin and get something that looks like an iterator which I can increment and compare and dereference? So there's a bunch of type properties that we want to be checking. So this happens a lot, again, if you're building generic libraries that have to ask for, that have to care about the properties of the given type, sometimes just to reject certain types and in other cases to specialize your decision based on properties of a type. So let's build something that detects whether a type is a container. There's a bunch of techniques for this. Even in C++98, we could sort of ask if a type has certain members, for example, or if a type has certain nested type defs, but in C++11 with decal type and with a bunch of further advances, we have easier solutions for this problem. So again, we want to build our own type traits which ask, does a type have a certain member or more generally, does a certain expression make sense for my type? Does it compile? And even maybe does it produce a certain type as a result? So for example, not just, for example, for the dereference operator on iterators, I actually wanted to produce a value. If I have a void returning dereference operator, that's a little fishy for a container. So we want to ask if a certain expression makes sense and maybe produces a particular type. So there's a very cool trick here introduced by Walter Brown, I think a couple of years ago at CPPCon, I was very impressed when I saw it first. There's a bunch of other ways to express the same thing, but this one is so clean and so concise that I really fell in love with this technique and I've been telling about it to people since. So basically, you have this super simple and weird looking template. This is actually a Lalias template which defines void t as void for any type. So this is a template, you could say void t of int, void t of float, void t of std vector, and it's always just void. It's always defined to be void. The point is not that it is void. The point is that if we try and use this thing, if we try and use void t with a type that's not well formed, with a type that's not valid, then this thing just has no definition. The thing doesn't make sense. So void t wouldn't be sensible, whereas if we use any valid type as the template parameter here, we would get void always, just regardless of what we put in. There's alternatives for this in the standard library, but it's really clean to just see it this way. So here's how we use it for isContainer in our example. Up top, there's the first version, the more general version of the isContainer template, and it has two template type parameters, t and another one, which is unnamed, I don't care what it's called, and it has a default type parameter value which is void. So this one is the more generic template, it's not a specialization, and this one is defined to inherit from std is array of t. So basically, if we go to that isContainer template up top and we ignore everything else on the slide, then it's basically equivalent to asking is t an array. If t is an array, then this template recognizes it as a container, and if t is not an array, then we don't recognize it as a container. So we've taken care of arrays separately. And isArray, of course, is defined in type traits, and we assume it works correctly. And then we have the specialization. It's occasionally unclear why this thing is even a specialization of the first thing. So how would you convince your friends that this second definition is a specialization of the first? It has fewer type parameters. It has fewer type parameters, right? So the one up top has two type parameters, even though the second one has a default value, but the one on the bottom only has one type parameter. So that's enough for me, I suppose. And this is container template is a specialization in case, well, t, the first argument is just the t we got passed in. And the second thing, the second type parameter, which has a default value of void over here, the second type parameter is that void t template specialized, well, sorry, parameterized with t iterator, right, with the nested iterator type def. And if we use this specialization, then I just inherit from a true type to indicate that yes, we are a container. So basically, if this specialization is chosen, then we deduced that t is a container. Okay, so for this specialization to be chosen, what needs to happen is that void t of that type is well-formed. If it is not, if our type is, for example, an int, then what we have over here is just int column, column, iterator. That doesn't make sense. That's not well-formed. And then substitution failure kicks in, and we just ignore this specialization. And we have our base case, which will then deduce that int, because it's not an array, is not a container. But if t does have a nested iterator type def, then this thing over here is well-formed, and this is just plain void, right? And then this is a specialization of the previous case, and this specialization is a better match, so the compiler, when doing the template specialization pattern matching, would pick this version and deduce that our type is a container because we inherited from true type. Why, just one final thing, why does it matter that this here is void? Why did they put void in here and not something else? I was looking for the same person to answer. Yeah, no, so what I'm asking is why does this have to be void and not say int, right? Because this has to be void, and the thing that happens is if the user of my template of isContainer doesn't provide the second type, right, so my user says isContainerOfInt. The user doesn't specify what the second type is, so if the user says isContainerOfInt, I would like both versions to be potential candidates. So in this case, isContainer, the first version, would be isContainerOfT and void, and this one would be isContainerOfT and whatever void T produces. So if void T produces void, we have our two candidates, and the more specialized one can be picked. But if here, I said int, for example, then when the user says isContainerOfWhatever, then what the user actually said is isContainerWhatever,int, right, and then the second specialization would just never be valid because void T doesn't produce an int, it produces void. So all the parts here matter, right? It does matter that we have void up there, it matters that void T returns void. Everything's important in this skeleton, if you will, for member detection. Now you might ask, can this be generalized further? And yes, it can. So here, we're just testing if a type has a certain nested type def, but we can make this further generic, if you will. So if I want to test that a certain expression, arbitrary expression pretty much on arbitrary types makes sense, and that's the trait I am checking for, that's the property I'm testing for, then the general recipe would be. We define an alias template for that specific test, and it's basically just the decal type of whatever this expression returns. So suppose I want to check if T1 has a member function called foo, which takes a T2, right? So I have this alias template, which is a template in T1 and T2, and it is declared as the decal type of this expression here, which declares a value of type T1 reference, and then invokes foo on it, passing in a T2, right? And the decal val function is just a very stupid silly little function from the standard library. It has no body, it's just a declaration, because we use it in context which do not require evaluation. So it's basically just declaring T1 for us or T2 for us. That's the only thing we care about. Once we have that test, we just plug it into our skeleton. So the generic version of does my condition, is my condition true for a certain pair of types, the one over here, the generic version, takes T1 and T2 and that dummy void template parameter, and the specialization takes T1 and T2 and whatever void T returns when invoked with my test, which is up there. So if that expression makes sense, if this thing here is well formed, then void T produces void and we pick the second specialization, and if it is not well formed, then we pick the first one and we reject that property. And we could even test if we wanted that my test T is not just well formed, we could ask what kind of thing it is. So I could add, for example over here, I could add, so is my test T of T1 and T2 actually say an int or a const reference or whatever else I wanted to assert? So we basically have now a generic recipe for checking properties of types thanks to this void T trick. This again, it requires compiler support. So for example, my usual go to compiler again, which is Visual C++, still has some restrictions around expression substitution failure is not an error, expression is finite, so it would actually reject a bunch of these examples. But the more conforming compilers, GCC, Clang, they're okay with this. And Microsoft is working on fixing the edge cases that still don't work. And actually this kind of template is pretty useful in the standard library as well. So just as an example, in the standard library, there is a type trait called is assignable, which just determines whether one type can be assigned to another using the assignment operator. You could easily implement it using this generic trick, right? So over here in the decal type body, we would have just decal val A assignment, decal val B, and we'd have to test if that is well formed. So standard libraries all over the world can now use this instead of requiring compiler hooks or some sophisticated one-off tricks. There's just a generic trick that works for all the cases. So that was member detection. And once we have that, let's talk about some ways, right, some strategies for actually using the property we discovered for choosing one of multiple algorithms. Again if we want to optimize STD copy, for example, for pointers to primitive types as opposed to the general case of just iterators we know nothing about. So there's three general strategies I want to show you, which are common in a bunch of different template libraries, including the STL. One is just explicit specialization when you write all the boilerplate yourself. The other is tag dispatch, which is useful and used a lot in the STL, where you have multiple versions of an algorithm. So basically the property you're testing is not binary, true or false. It has multiple degrees of being true. And there's also STD enable if, which is usually used if you want to disable a certain function, if you want to remove a certain function from the set of overloads that you would want the compiler to consider. So let's take a look at a few examples. Again, just an overview of the tricks that a lot of libraries use. So this rather verbose thing on the screen is an attempt to specialize the sort implementation, just a general sort that takes iterators for two cases. One when the type we're sorting just has general properties, is generally comparable, right? So it has a less than operator, which provides order. And the other case is if it's hashable, if there is a way to produce hashes from values of that type. So if it is hashable, maybe I'm going to use a different sort algorithm like radix sort, and if it's not hashable, I'm going to use something else. It's just an example. I'm not saying there's a practical use of this kind of sort implementation. But we want to ask about the property of the type and then just redirect to two different implementations. So I can have this base case of a sort imple class template, which is undefined. Basically I don't care about it because I am going to have specializations for both of the cases. So this base template is a template of some type and the Boolean. And then I have two specializations. I have one for some type and false, and another for some type and true. So I basically covered all the cases because Booleans can be either true or false. So there shouldn't be any case where we actually get to the base template and the compiler would complain that we haven't actually defined it. So for false, I have one definition of a static sort function, and for true, I have a different definition of a static sort function. So basically this is just a way of picking overloads at compile time. I have two functions in two different class templates, and I'm choosing the right one based on whether some property is true or false at compile time. So now I just have to ask, is that property true? And redirect to one of the options. So in this version, which is the publicly accessible one, that's the thing that clients actually invoke. In this version, I specialize sort-imple, I parameterize sort-imple by whether the value type of that iterator has some property. So is hashable v? That's not a standard library thing, but it's a type trait that we built using the techniques we talked about previously. So sort-imple of my iterator type, and either true or false, just picks one of the two class template specializations we had over here, and then I invoke the static sort method on that passing in my iterators. So we have just successfully picked one of two implementations based on a Boolean property of some type. This is a bit verbose, but it works, and in some cases, you might actually prefer it. For example, if that type that you're using actually has to have some state and member functions, it's actually useful to just pick one of multiple class template specializations and then just work with that class template, kind of like the strategy pattern, except you're doing it in compile time and not at runtime. And this can be obviously expanded further to a bunch of additional examples. The other alternative, which is pretty common in the standard library, is tag dispatch. This doesn't require class template specialization, just multiple overloads of a certain function, and the overloads are different only by usually a trailing type which can take multiple type values. So here's a classic example from distance. This is an STD algorithm that finds the distance between two iterators, right? How many elements are in the range between two iterators? So this is the publicly accessible declaration. So distance takes two iterators. What it returns is, well, whatever iterator traits difference type is for my iterator type. So conveniently, we have iterator traits, which is supposed to tell us things about iterators. This is yet another example of a meta function that takes types and returns values and types for us. And then I invoke distance helper, which is not a publicly accessible interface, and distance helper takes the two iterators first and last, as well as an additional parameter. And this one is also obtained from iterator traits. So in iterator traits, I have iterator category, which is a type. So I instantiate that type over here, and that's what I pass to distance helper. So now distance helper can be overloaded for various types that iterator category can return. Just for simplicity, suppose iterator category is sometimes an int and sometimes a float. So I can now build two distance helpers, one that takes an int and one that takes a float as the third parameter, and in such a way specialize my implementation. Iterator category, fortunately, doesn't return int or float. It's a meta function that returns one of multiple types, indicating what kind of iterators we have on our hands. So it could be forward iterator, an input iterator, bidirectional iterator, random access iterator, and so on. And here's what the actual helper could look like. So for random access iterator tag, which is the iterator category for random access iterators, my implementation just uses the minus operator, right? So we just find the distance between the two iterators. And for anything else, this is the second version of distance helper, it takes iterator tag base, which is the base class of all the other iterator categories, of all the iterator categories. So for iterator tag base, we have the implementation here, which declares a counter and then just traverses the range, incrementing the counter till we reach last, right? So while first is not last, increment last, increment n till we get to the end and then return n. So this is going to be the linear time version, and that's going to be, hopefully, a constant time version. And we just used a property, a type property, returned by iterator category to choose one of the two. So that's a pretty common technique as well. And a third example I want to show you is an A... Just like a lot of classes. And it also has this constructor over here, which takes a universal reference to any t. And the reason you'd usually have that kind of constructor, does it work now? Okay. So the reason you'd usually have that kind of constructor, which takes a universal reference, is not to emulate a copy constructor and a move constructor on your own type, but rather to enable construction from some other type. So for example, maybe my widget, it can actually be constructed from, for example, a tuple of configuration values. And I want to optimize for two cases, one when I am passed an r-value reference, which I can move from, and the other when I'm passed a const reference to an l-value, which I can only copy from. That's a pretty common situation. But even ignore the reason why I actually have that kind of templated constructor. The issue here is hiding. What can happen is that if the user of my widget class initializes a widget and uses an l-value reference to a widget, which is not const, so basically just widget ampersand, right, an l-value reference to a widget which isn't const, then the compiler can choose between my copy constructor, which takes a const reference to a widget, and this template constructor, which was never intended for situations where t is a widget, but it would apply in that case, and it would be picked, because this constructor works where the t ref ref actually resolves to just a widget ampersand, to an l-value reference to a widget. So we have a constructor that takes a const reference and a constructor which takes a non-const reference, and that second constructor would be preferred. So essentially, we built a universal constructor which hides our own copy constructor. This is undesirable. So we can ask the compiler, essentially, to not pick that specific overload, that specific constructor, if I'm using a widget as t. So the way this typically works is that somewhere in the signature, and there's a lot of places you could actually put that in the signature, somewhere in the signature, you put enable if, and enable if is very similar to void t, actually. It just determines whether an expression is well-formed, and then it's used for substitution failure to remove that overload from the set of overloads that can be considered. So in this case, the expression I'm passing to enable if is not is same t widget reference value. So basically a Boolean which says whether or not t is the same thing as an l-value reference to a widget. So if t is the same thing as an l-value reference to a widget, this expression, because of the not here, this expression is going to be false. And then we have enable if of false, and enable if of false is not defined. So it's not a type, it's not any type, whereas enable if of true is void, kind of like our void t template. So in the case where enable if t here produces void, this template overload is considered valid, and in the case where enable if t takes false, and it is undefined, this constructor is just removed from the set of candidates because it is a substitution failure when trying to match the template arguments, the template type arguments. You could place that enable if in a bunch of additional places, maybe in, when reviewing template libraries, you might have seen enable if as an additional parameter, right? So in some cases you put it as an additional parameter which has a default null value. You could use enable if as the return type, not in a constructor though, constructors can't have declared return types, but in other functions you could use enable if t is the return type, again just to get the compiler to consider that type as part of the function's signature. Again if it doesn't match, then this signature, that overload is removed from the set of candidates that the compiler would consider. So in this way we could just disable this overload in certain circumstances, and this trick is used a lot in the STL, yeah? Is there a way to apply this trick if it's not in some kind of place? Is there a way to apply it? Without the constructor constructors? What do you mean? If you have templates like the NT of rigid and you have a copy constructor and a move constructor, and you wanted it to choose the copy constructor in the cases where it was actually copying instead of moving. As you said, the move constructor will always be preferred if it's a long const. So if you declare a copy constructor and the move constructor, then the move constructor will be chosen if you have an r-value reference, if you have a reference to a temporary, if you have a reference to an l-value, then the copy constructor will always be chosen automatically. Just think about it, your move constructor is going to be moving, so it's going to destroy the object. If you have an l-value, that would be extremely unsafe. You don't need this trick at all if you just declare a copy constructor and a move constructor and you want the compiler to pick. So in that case it doesn't actually collapse to its own reference? It was not? It didn't collapse to just a reference in that case? So you're saying no template here, no universal reference, just a copy constructor and a move constructor, right? No, I'm saying that the class is template. Oh, that's fine. And the constructors, what do they take? Do they take widgets or do they take one of the template arguments? Type name, T. Type name, T. So you still have a universal reference on the T. But just one constructor? Both, a copy and a move constructor. So they're not a copy and a move constructor if they don't take the exact type, right? So if you have a constructor that takes, for example in this class, if I had a constructor that takes an int, you wouldn't say that's a copy constructor or a move constructor. It's just yet another constructor. So if this thing was a template of whatever and you had a constructor taking whatever and not widget of whatever, that's not a copy and a move constructor. It's just yet another constructor. Yeah. Hopefully that clears things up. Okay. So we do have a few minutes left. So I want to show you real quick just one more example of using sort of the same techniques for a slightly different scenario for compile time computation. And first, I just want to make sure we're all familiar with constexpr. So basically in the good old days, to perform compile time computation, you'd have to do stuff like that with recursive templates. That's just a classical example. I'm sure you've all seen that thing. So for example, here I'm calculating factorial by having a class template specialization for size t where the base case is defined as one. And then all the other cases are recursively invoking that class template until it's specialized down to zero. So first of all, we can replace a lot of these recursive templates with constexpr, which was introduced in C++11. So when applied to a function, constexpr means that in some cases, the value that this function returns can be obtained at compile time. So you don't have to actually invoke it at runtime. You can just sort of run through that function at compile time and get the output. So here's factorial as just a constexpr function. And obviously, the advantage here is that even though the thing is calculated at compile time, you still specify it exactly the same way as any other function that would be calculated at runtime. Furthermore, you could use that factorial function with values that are known at compile time, and then the result is known at compile time, or with values that would only be known at runtime, and then the result would only be known at runtime, which is nice. In C++14, a lot of restrictions on constexpr were lifted. So for example, now in constexpr functions, you can use loops, and you can declare local variables, which you couldn't in C++11, where the whole thing had to be a single return expression. So that opens the door for a bunch of additional things that you can express as compile time computation. And you can even now have types which are constexpr essentially. So here's, for example, the complex type. Tuple has similar situations. So here's a complex type where the constructor can be constexpr, and it has a real and a set real function, which are constexpr, and the conjugate function that can be constexpr. So basically, we can now express computations on complex numbers, and they will be performed at compile time, which is rather cool. I think what's even more cool is that const and constexpr are two totally distinct concepts, right? So for example, here's a function, which is constexpr, but it's not const. It's actually mutating an object. That mutation just happens at compile time. So that's what we're saying by using constexpr here. This function here, it's mutating a value, but it's happening at compile time, so that's what constexpr means. Great. So here's the very, very quick overview of constexpr. Some simple uses are rather nice. So for example, you can replace the horrible array size macro, which takes an array, a statically defined array, and returns the number of elements in that array. You can replace that with a constexpr function template, which is where the template arguments are the type and the number of elements in the array, and we just return the number of elements. And that array size can be used at compile time situations. So for example, you could declare an array whose size is array size of some other array, which is a rather common use of array size. So that's a compile time known value. Another example is the power function, which can be calculated recursively. So 2 to the power of something comes up a lot. So these are simple uses, and there's a bunch of them in the library and in code you'd write yourself. But here's a slightly less obvious use, where constexpr can actually replace a bunch of class templates, which you would use to define meta functions before. So our task here, in this particular case, is to build a compile time facility, a compile time function, basically a meta function, which takes a certain type trait, a Boolean property of types, such as is integral or is floating point or is no throw move constructible, some kind of Boolean property of types, and an open collection of types, just any types we want, t1, t2, t3, an arbitrary number of types. And we want this thing here, and f, to evaluate whether this Boolean meta function is true for all my types, t1, t2, t3, and return true or false, which would be known at compile time. So this is a classic scenario, which you would solve using class template specialization before constexpr was available. You'd have to build a couple of class templates recursively. They would have to derive or extend each other. Here's the constexpr solution, which for me anyway, in some cases, is clearer. So here's the base case for endf for this little function. The base case doesn't take any types. It only takes the operator. It only takes the binary function, the Boolean function, such as is integral. And it returns true, because if you apply that function to no types, then we could say it is true for all the types, for all the no types we have. And then the interesting case, the recursive case is over here, where we have that operation, the Boolean property of types. We have the first type, and we have all the rest of the types, and the rest can also be empty, so we could be down to just one thing. And we just perform a recursive invocation, right? So we ask, is op of t true? And the recursive invocation for all the rest of the types is a true as well. And that's what we return. And the whole thing, of course, is constexpr, so it's all evaluated at compile time. It's not like at runtime you're actually going to have any recursive invocations. That whole thing just folds down to true or false at compile time. And for me, in some cases, this constexpr function style is more readable and more understandable than class templates, which would have to interact with each other through specializations, especially if the thing you're working with is values and not types. So in this case, I'm working with values. I have true, false, which I have to combine in some way, and not types, which would be harder to combine using just functions. So my final example from the constexpr area is one I've come across about a year ago, maybe a little more, which is parsing strings at compile time. So here's a little class called cstr for compile time string, which has a constructor from an array of characters with a known size. So it can basically be initialized from literal strings, right? literal strings known at compile time. So that's an array of characters, and the size is also known. What this constructor does is just initialize members, the pointer to the beginning of the string, and the length of the string. And now I can have, in that class, multiple constexpr operations which interact with these fields. So for example, I could do length function, which would return length. I can do an isEmpty function, which returns whether length is 0. I could also do a function which looks for a certain character in the string and returns the first occurrence. And that function would still be constexpr because this whole thing is performed at compile time. And one example of using it is for printf-like situations where I want to test that my format string is valid. So just think about it, if the format string is a compile time literal string, which happens in a lot of cases, you can validate it at compile time, not waiting until run time to make sure the format string is valid. So in this very simple example, I have a static assertion which makes sure that the count of percent signs in my format string is the same as the number of arguments passed to the printf function. So that's obviously a simplification because in printf format strings, you can have double percent sign and that's not a placeholder. But the general idea still holds. We can test at compile time whether a certain string literal has a certain number of percent signs and reject at compile time that format string if it doesn't. So for example, if I invoke my printf function with two arguments but only one percent sign, the compiler could complain and that static assertion would fire and tell me number of arguments doesn't match the format string. So obviously this is just a prototype, right? But it can be used in a lot of situations where I have to validate strings at compile time. For example, imagine a regular expression constructor that tests that the regular expression is well formed, a bunch of things that are quite easy to express once we have constexpr because you can essentially reuse the same code, the same algorithm for testing things at compile time and at runtime. So that's just a wrapper case for my examples. Right, so we have about three minutes left so if you have any questions, there will be a little time I hope. I hope you've seen some examples of using template metaprogramming in a variety of tasks in both libraries and applications. So admittedly, a lot of these examples are from the library world, implementing STL algorithms, optimizing them and so on. But hopefully application level examples can also be extracted from these samples. And with the tools we have in C++ today such as DecalType, such as constexpr, it's a lot easier to build these kind of solutions than it was in C++ 98. Now if you're seriously considering investing in TMP libraries, instead of building these basic tools yourself, there's a bunch of options to choose from, right? So you don't have to build the basic combinators, for example, for testing whether a certain property holds for multiple types, that kind of thing. You don't have to build yourself unless you just enjoy the process. I enjoy the process, but still you don't have to build these things yourself. There's a bunch of libraries including in Bust, some modern, some older, which provide solutions to common tasks that you have to perform at compile time. So this is all quite fun and hopefully will be applicable to at least some situations you encounter. And if you have any questions, we have about three minutes. Yeah. Yes. Why would you use such a station for the helpers? Instead of? Instead of the training type. Instead of? The extra pyramid. Okay, so just to repeat the question, why did I show you an example of using class template specialization and tag dispatch instead of just using one of them? So first, it's nice to see multiple options. And second, tag dispatch is usually used when you're trying to invoke a function. If you have a whole class template that you want to pick and that class template would have members and would have behavior, so state and you have multiple functions to invoke, I think it would be more convenient to use specialization. I think it's also a matter of taste to some extent. All right. Well anyway, thank you very, very much for coming and I'll have some samples for you on Twitter later if you'd like to explore some labs yourself and the examples I've shown you here today. I hope you enjoyed the rest of NDC. Thank you very, very much for coming. Thank you. Thank you.
examples of compile time computation with be pre-computed at compile time or solved we'll be using throughout this talk is template available in the library, and based on other constructor as no accept, and that will produce some error message if T doesn't meet the rather sort of making sure your implementation is order to pick, we have to ask, is this thing a container. There's a bunch of techniques for that dummy void template parameter, and the this rather verbose thing on the screen is an specific overload, that specific constructor, if template arguments, the template type arguments. You could place that enable if in a bunch of And that array size can be used at compile time the rest of the types, and the rest can also be the same code, the same algorithm for testing investing in TMP libraries, instead of building to build the basic combinators, for example, for