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!

55 thoughts on “Some interesting usages of std::function

  1. Pingback: Jaime
  2. Pingback: gordon
  3. Pingback: Guy
  4. Pingback: anthony
  5. Pingback: Michael
  6. Pingback: max
  7. Pingback: lynn
  8. Pingback: Wade
  9. Pingback: Kirk
  10. Pingback: philip
  11. Pingback: william
  12. Pingback: Martin
  13. Pingback: Joseph
  14. Pingback: gordon
  15. Pingback: Paul
  16. Pingback: clarence
  17. Pingback: roger
  18. Pingback: leslie
  19. Pingback: nathaniel
  20. Pingback: Albert
  21. Pingback: Alfonso
  22. Pingback: rick
  23. Pingback: Jack
  24. Pingback: Gary
  25. Pingback: Vernon
  26. Pingback: Lyle
  27. Pingback: mark
  28. Pingback: ricardo
  29. Pingback: Larry
  30. Pingback: sean
  31. Pingback: Ramon
  32. Pingback: Gene
  33. Pingback: Harry
  34. Pingback: perry
  35. Pingback: Patrick
  36. Pingback: Carlos
  37. Pingback: Sergio
  38. Pingback: Tommy
  39. Pingback: alex
  40. Pingback: tracy
  41. Pingback: salvador
  42. Pingback: Lynn
  43. Pingback: Troy
  44. Pingback: lawrence
  45. Pingback: morris
  46. Pingback: marshall
  47. Pingback: Bobby
  48. Pingback: Ralph
  49. Pingback: Gary
  50. Pingback: Richard
  51. Pingback: Edward
  52. Pingback: ken
  53. Pingback: Thomas
  54. Pingback: julio

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>