Some interesting usages of std::function

The any-event dispatcher

The std::function class allows us to easily store any function object. We can use this feature in order to avoid type-related problem, like in events systems.

#include <iostream>
#include <functional>
#include <type_traits>
#include <unordered_map>

class EventsDispatcher {
public:
	/// \brief Registers a callback which is going to be called by the injectEvent function
	template<typename TEvent, typename TListener> void			registerListener(const TListener& function)				{ _registerListener<TEvent>(function); }

	/// \brief Calls all the corresponding callbacks
	template<typename TEvent> void								injectEvent(TEvent& ev)									{ _injectEvent(ev);  }



private:
	// for each event type, we have a list of callbacks
	// these callbacks are of the form std::function<void (void*)> because we will convert between the &event and void*
	std::unordered_multimap<const std::type_info*,std::function<void (void*)>>			_listeners;


	template<typename TEvent, typename TListener>
	void _registerListener(const TListener& function) {
		static_assert(!std::is_array<TEvent>::value, "You cannot register an array as an event type");
		static_assert(std::is_convertible<TListener,std::function<void (TEvent&)>>::value, "Unvalid callback for this event type");

		_listeners.insert(std::make_pair(&typeid(std::decay<TEvent>::type), [=](void* ev) { function(*static_cast<TEvent*>(ev)); }));
	}

	template<typename TEvent>
	void _injectEvent(TEvent& ev) {
		auto range = _listeners.equal_range(&typeid(std::decay<TEvent>::type));
		for (auto i = range.first; i != range.second; ++i)
			(i->second)(static_cast<void*>(&ev));
	}
};

// example of an event type
struct KeyboardEvent {
	explicit KeyboardEvent(wchar_t text) : text(text) {}

	wchar_t text;
};

// example of an event callback
void printKeyboard(const KeyboardEvent& ev) {
	std::wcout << ev.text << std::endl;
}


int main() {
	EventsDispatcher dispatcher;

	dispatcher.registerListener<KeyboardEvent>(&printKeyboard);
	dispatcher.injectEvent(KeyboardEvent(L'a'));


	#ifdef _WIN32
		system("pause");
	#endif
	return 0;
}

Lazy evaluation

Instead of writing setters like void setXXX(int); you can write void setXXX(std::function<int ()>);. The class will then store the function and call it only when needed, thus avoiding the need for the class owner to call the setter repeatedly.

This is especially useful for continuous data, eg: object.setPosition([]() { return float(clock()) / float(CLOCKS_PER_SEC); });

#include <ctime>
#include <iostream>
#include <functional>


class TextPrinter {
public:
	void		setTextToPrint(wchar_t text)								{ setTextToPrint([=]() { return text; }); }
	void		setTextToPrint(const std::function<wchar_t ()>& f)			{ _function = f; }
	
	void		print() const												{ std::wcout << _function() << std::endl; }


private:
	std::function<wchar_t ()>			_function;
};


int main() {
	TextPrinter printer;

	wchar_t character = L'a';
	
	// 'classical' way to do: updating the data manually
	printer.setTextToPrint(character++);
	printer.print();
	printer.setTextToPrint(character++);
	printer.print();
	printer.setTextToPrint(character++);
	printer.print();

	// more convenient way
	printer.setTextToPrint([&character]() { return character++; });
	printer.print();
	printer.print();
	printer.print();


	#ifdef _WIN32
		system("pause");
	#endif
	return 0;
}

Storing objects thanks to shared_ptr

Thanks to shared_ptr you can use a std::function as a storage for any object type, even if not a function object.

#include <functional>
#include <iostream>
#include <memory>
#include <string>

// example of a class which handles the keyboard (real implementation not shown)
class KeyboardHandle {
public:
	void setTextCallback(std::function<void (const std::wstring&)> f) {
		_callback = f;
	}

	void simulateText(const std::wstring& text) const {
		_callback(text);
	}

private:
	std::function<void (const std::wstring&)>		_callback;
};

// example of a class which can print text on the screen
class TextPrinter {
public:
	void print(const std::wstring& text) const {
		std::wcout << text << std::endl;
	}
};

// this function sets the keyboard so that it will automatically print the text written on it
void initKeyboard(KeyboardHandle& kb) {
	auto printer = std::make_shared<TextPrinter>();
	kb.setTextCallback([printer](const std::wstring& txt) { printer->print(txt); });
}

int main() {
	KeyboardHandle kb;
	initKeyboard(kb);

	// apparently there isn't any trace of the TextPrinter instance but it still exists in memory
	// and whenever a text is written on the keyboard it will automatically be printed
	kb.simulateText(L"hello world");

	#ifdef _WIN32
		system("pause");
	#endif
	return 0;
}

And more...

The std::function is really one of the most interesting features of C++0x.
There are a lot of different ways to use it, so don't hesitate to try out!

One thought on “Some interesting usages of std::function

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>