C++ Trivia: Writing functions that take a function as a parameter

So I was recently writing some code to test some performance characteristics of lists and vectors. This was prompted by my watching Bjarne Stroustrup’s keynote from Going Native 2012, where he explains yet another reason why vector should be the favored data structure: it often performs better than list, even when computer science common sense tells us that it should not. (See Bjarne Stroustrup: Why you should avoid Linked Lists (Youtube) for more about that.)

So I was using the Windows performance counter APIs, QueryPerformanceFrequency and QueryPerformanceCounter, and I was using them a LOT, since I was trying to measure what kind of impact each part of the testing had on the system. (E.g., how much relative time did it take to find the point at which we wanted to insert or delete an item vs. how much relative time did the actual insertion or deletion take.)

Since I have also been boning up on new language features in C++11/14, I decided that I wanted to figure out how to write a function that would take a lambda expression to make this all easy to use. I wanted to be able to call something like the following (which is completely trivial, but shows how I might want to use this functionality):

auto time = my_timer_function([](){ Sleep(500); });

Now the way I have done something like this in the past is to declare a function prototype, and then a function for each thing I want to measure, and then pass them into a function that takes a parameter of the type of the first prototype. If that sounds like it’s a bit hard to follow, that’s just because it’s a bit hard to follow.

Well in C++ they added a few new features to make this much simpler and easy to understand: Lambda expressions and the std::function type. Instead of defining a function prototype (which is always confusing syntax and I almost never get it 100% right the first time), you can use a parameter of type std::function, which is a template that takes the function signature as a parameter. So the following block defines a my_timer_function that takes in a function that looks like void fn( void ), and measures how long that function takes to complete.

auto my_timer_function( std::function fn ) -> double
{
	LARGE_INTEGER countsPerS = { 0 };
	LARGE_INTEGER beginElapsedCounts = { 0 };
	LARGE_INTEGER endElapsedCounts = { 0 };

	VERIFY( QueryPerformanceFrequency( &countsPerS ) );
	VERIFY( QueryPerformanceCounter( &beginElapsedCounts ) );

	//	Call the fn we are supposed to measure
	fn();

	VERIFY( QueryPerformanceCounter( &endElapsedCounts ) );
	return ( double( endElapsedCounts.QuadPart - beginElapsedCounts.QuadPart ) * 1.0 * 1000 / double( countsPerS.QuadPart ) );
}

The magic of the compiler makes it so you can pass this an actual function, or a lambda expression, or even a functor (object that can look like a function). So any of the following will work just fine…

// Lambda expression
auto time = my_timer_function( [](){ Sleep( 2000 ); } );

// Function
void MyFn()
{
	Sleep( 2000 );
}
...
auto time = my_timer_function( MyFn );

// Functor
struct MyFunctor
{
	void operator()()
	{
		Sleep( 2000 );
	}
};
...
auto time = my_timer_function( MyFunctor() );

Leave a Reply

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

Complete the following to verify your humanity: * Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.