Pseudo Functors and Template Magic
A functor is an object that works like a function. That is it overloads operator()
. They are useful when you need to create a series of functions each of which works mostly the same way, but you want that instance of the function to hold some state.
The classic example is the “add x” functor. I got this example from stackoverflow.com, but it is a staple of functor tutorials:
// this is a functor struct add_x { add_x(int x) : x(x) {} int operator()(int y) { return x + y; } private: int x; }; // Now you can use it like this: add_x add42(42); // create an instance of the functor class int i = add42(8); // and "call" it assert(i == 50); // and it added 42 to its argument
Each instance of the add_x
functor adds a different constant. Functors are usually a bad idea. It is way cleaner to pass state in through the function arguments than to hide it in a functor. In most cases when you need functions and data to travel together you’re better off creating a class with normal methods.
Functors can sometimes be useful in template programming, when you want to hide implementation details from the user.
One of the downsides of functors is that they need to be declared as objects first before they are used later. But sometimes you want a one line solution. That is you want to have what appears to be a templatized function, but that function needs to have some of its own data storage.
For this you can use the class constructor to work much like a function call. Take the following problem: I have a string that I want to filter in such a way that the filtered string is usual longer than the input string. I only need it for a short time. This is for a web project where I want to take characters like “<l” and turn then into “<”.
Once output to the page renderer I don’t need the string any more.
The usual way to do this would be something like this, allocate a string big enough, do the conversion, output it, and delete the filtered string:
char* newStr = new char[strlen(str)*6];
convertToWeb( str, newStr );
outStream << newStr;
delete newStr;
[/cpp]
But in my case it was uglier because I already have classes to stream objects, so it was more like:
[cpp]
MyStream tmpStream;
tmpStream << object;
const char* str = tmpStream.getBuffer();
char* newStr = new char[strlen(str)*6];
convertToWeb( str, newStr );
outStream << newStr;
delete newStr;
[/cpp]
Where ideally I'd like to do something like this:
[cpp]
outStream << webalize( object );
[/cpp]
The solution is a templatized class that looks like this:
[cpp]
class webalize
{
public:
template
{
MyStream tmpBuf;
tmpBuf << obj;
// boring string coversion code here
char* newString = doStuff();
mBuf << newString;
}
friend MyStream& operator<<( MyStream& os, const webalize& str )
{
os << str.mBuf.getBuffer();
return os;
}
protected:
MyStream mBuf;
};
[/cpp]
By putting the template on the constructor instead of the class helps the compiler deduce the type. Now any class that already supports the stream interface can get transformed into a web friendly output version in what looks like a function call.
Of course, this isn't really a functor, but just a class that does something useful in the constructor. In this case the return type of the "pseudo functor" is the type of the class itself. But you could get around this by implementing a cast operator of the return type you need.
Resources:
Functors: Function Objects in C++
A tutorial on functors
C++ Functors and their uses
A simple explanation of functors
automatic type deduction
A trick to get compilers to auto-deduce template parameters
C++ functor and function templates
More on deducing template parameters in templatized functors