fbpx

Function objects are simple but don’t let that fool you. You can use them in clever solutions.

How do you actually use functors?

A really great example is in the C++ standard library collection classes. Some of the collection classes support sorting. In fact, some of them require sorting. Now you might think, okay, what’s so special about that? And if all you have is a collection of numeric types or maybe a collection of dates, then, yes, sorting is fairly easy. But wait a moment. Which way? Should your collection hold 1, 2, 3, or should it hold 3, 2, 1? Even numeric values have a little extra functionality.

What about custom classes with several member data fields? Should they all be looked at? In what order? Or do you let the user change the sort order by clicking column headers? What if you want to sort by one property and then another? Let’s say you have a list of items for sale. Maybe the user wants to see them sorted by price. That’s good but what if a whole bunch of them all cost the same? Should similar priced items then be shown in a random order? Probably not. It makes sense to sort the items by price since that’s what the user selected but then sort them again by name for items of the same price.

You can write your own function object that knows exactly how to work with whatever properties you need. But using functors, gives you more benefits than just this.

Listen to the full episode for more on functors, or you can also read the full transcript below.

Transcript

This episode continues the explanation of function objects. Now that you know what a functor is and how to write one, I’ll explain more about how to use them.

I mentioned that because a functor is an instance of a type that you can pass it around and make use of instance data to customize its behavior. But you could, with a bit extra work, get a function pointer to do something similar. Not quite, but almost. There’s more though than just this to a functor.

Because its an instance of a type, we can use that type in templates. A method has a signature but a class has both a type and potentially internal data.

That actually sounds like just more theory. How do you actually use functors?

A really great example is in the C++ standard library collection classes. Some of the collection classes support sorting. In fact, some of them require sorting. Now you might think, okay, what’s so special about that? And if all you have is a collection of numeric types or maybe a collection of dates, then, yes, sorting is fairly easy. But wait a moment. Which way? Should your collection hold 1, 2, 3, or should it hold 3, 2, 1? Even numeric values have a little extra functionality.

What about custom classes with several member data fields? Should they all be looked at? In what order? Or do you let the user change the sort order by clicking column headers? What if you want to sort by one property and then another? Let’s say you have a list of items for sale. Maybe the user wants to see them sorted by price. That’s good but what if a whole bunch of them all cost the same? Should similar priced items then be shown in a random order? Probably not. It makes sense to sort the items by price since that’s what the user selected but then sort them again by name for items of the same price.

Well, the container classes have absolutely no idea how to do all this. I’ll explain how functors can help right after this message from our sponsor.

One of the template parameters that is sometimes available depending on the collection is a sort operation. Let’s say you want to create a set to hold integers. If you just write set<int>, then you get the default sort operator less.

What is less though? I’m not talking about the concept of what it means for one thing to be less than another. I’m talking about the specific default less that you get when you don’t specify anything else when creating a set.

Less is a predefined functor. It’s a template class that uses operator less than on two values that match the template type. The less functor is a bit more specialized. It’s called a predicate. A predicate is a functor that meets some extra requirements. The most important requirement is that the return type should be bool for predicates. This makes sense because predicates are there to answer simple questions. In this case, we just want to know if one numeric value is less than another or not. I’ll get to the other requirement in just a moment.

So back to the set collection again. What if you want to put instances of your own custom class into a set. If you don’t specify otherwise, you’ll get the less predicate as the sorting functor. And this uses operator less than. It’ll all work just fine as long as your class implements operator less than or if your class instances can be automatically converted to some type that does implement operator less than. This is not always a good thing to provide.

When you’re designing your own class, you really should implement operator less than if it is obvious and expected what the outcome will be. If your class wraps up some numeric value in an interesting way, then it probably makes sense and would be expected to provide an operator less than.

But what if your class represents inventory items? It’s not so clear anymore what property to use when comparing them. Should you use size? How about weight? Cost? Color? I don’t even know what sorting by color would mean let alone if that should be used. The problem is that any of these is a valid sort criteria. Only the user can decide how to display a group of inventory items.

We’re not really talking about displaying item though. We just want to put these things in a collection. And for that, we need something to sort by. You may want to use an identity field for this. That’s a great field to sort by because it won’t change and will make it fast to find items if you know the identity.

So you create a functor that knows how to sort your inventory items by an identity field that the user will never see. You can then provide that functor to your set collection to use for the sorting.

And this goes to one of the biggest strengths of functors. They’re types. And because you used your custom functor when creating your set, it becomes part of the type of the set too. This means that the compiler can help you if you ever try to mix sets created with different functors. They’ll be different types and you’ll get compile errors.

Alright, just one more topic today to finish. Back to the other requirement of a good predicate. They should be stateless. What does that mean? It means that if you call the functor, then that should not change anything inside the functor. It shouldn’t change any data members. The reason this is important is because the collection may decide to use your functor however it wants. You have no control over this. All you do is write the functor and give it to the collection. If you make the functor return a bool and think that’s good enough, then it might be. You don’t know. It’s better to be safe and make sure that if the collection decides to call you predicate functor multiple times, that you don’t start returning different responses based on how many times it’s called. That’s what I mean by it should be stateless. The collection might call your predicate with some values and if it ever needs to call your predicate again with those same values, then you need to make sure that you return the same result as the first time.

If not, then this would be like going to a restaurant and replying that you want coffee when asked what you want to drink. Then replying that, no, you want tea if asked again. And replying that you want water if asked a third time. You’re not going to get the drink you want when you keep changing your answer. So make your predicates stateless so they only look at the values passed and no other state can affect the result.