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!

107 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
  55. Pingback: Chad
  56. Pingback: derrick
  57. Pingback: robert
  58. Pingback: Jimmie
  59. Pingback: Johnnie
  60. Pingback: Lee
  61. Pingback: Harvey
  62. Pingback: lewis
  63. Pingback: jeff
  64. Pingback: Bryan
  65. Pingback: andy
  66. Pingback: Shaun
  67. Pingback: Fredrick
  68. Pingback: brent
  69. Pingback: billy
  70. Pingback: Benjamin
  71. Pingback: adam
  72. Pingback: Aaron
  73. Pingback: lance
  74. Pingback: dale
  75. Pingback: vincent
  76. Pingback: timothy
  77. Pingback: John
  78. Pingback: mathew
  79. Pingback: Evan
  80. Pingback: Peter
  81. Pingback: Alexander
  82. Pingback: mitchell
  83. Pingback: Jeremy
  84. Pingback: Billy
  85. Pingback: Joel
  86. Pingback: Rodney
  87. Pingback: jeremiah
  88. Pingback: chester
  89. Pingback: Brent
  90. Pingback: Darrell
  91. Pingback: Ernesto
  92. Pingback: Gilbert
  93. Pingback: Edgar
  94. Pingback: trevor
  95. Pingback: philip
  96. Pingback: Kirk
  97. Pingback: Travis
  98. Pingback: wallace
  99. Pingback: kyle
  100. Pingback: Enrique
  101. Pingback: isaac
  102. Pingback: Armando
  103. Pingback: edward
  104. Pingback: Clyde
  105. Pingback: salvador
  106. Pingback: milton

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>