1
0
mirror of https://github.com/wqking/eventpp.git synced 2024-12-27 00:17:02 +08:00
eventpp/doc/argumentadapter.md

4.9 KiB

Argument adapter reference

Description

The header file eventpp/utilities/argumentadapter.h contains utilities that can cast pass-in argument types to the types of the functioning being called. It's as if the argument types are casted using static_cast for most types or static_pointer_cast for shared pointers.

For example,

struct Event
{
};

struct MouseEvent : public Event
{
};

eventpp::EventDispatcher<int, void (const Event &)> dispatcher;

// Below line won't compile because the listener must `const Event &` can't be converted to `const MouseEvent &` explicitly.
//dispatcher.appendListener(ON_MOUSE_DOWN, [](const MouseEvent &) {});

// This line works.
dispatcher.appendListener(ON_MOUSE_DOWN, eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent &) {}));

Utilities reference

Header

eventpp/utilities/argumentadapter.h

API reference

template <template parameters>
ArgumentAdapter<template parameters> argumentAdapter(Func func);

Function argumentAdapter receives a function func, and return a functor object of ArgumentAdapter. ArgumentAdapter has a function invoking operator that can cast the arguments to match the parameter types of func. The return value of argumentAdapter can be passed to CallbackList, EventDispatcher, or EventQueue.
If func is a std::function, or a pointer to free function, argumentAdapter can deduce the parameter types of func, then argumentAdapter can be called without any template parameter.
If func is a functor object that argumentAdapter can't deduce the parameter types, argumentAdapter needs a template parameter which is the prototype of func.
ArgumentAdapter converts argument types using static_cast. For std::shared_ptr, std::static_pointer_cast is used. If static_cast or std::static_pointer_cast can't convert the types, compile errors are issued.

Below is the example code to demonstrate how to use argumentAdapter. There are full compile-able example code in file 'tests/tutorial/tutorial_argumentadapter.cpp '.

// In the tutorials here, we will use two event class, MouseEvent derives from Event.
// The callback prototype in EventDispatcher is reference or pointer to Event,
// then we should only be able to add listeners that only accept reference or pointer to Event,
// not MouseEvent.
// But with argumentAdapter, the listeners can accept reference or pointer to MouseEvent,
// and argumentAdapter converts any reference or pointer to Event to MouseEvent automatically, as
// long as object pointed to the reference or pointer is a MouseEvent.

class Event
{
};

class MouseEvent : public Event
{
public:
	MouseEvent(const int x, const int y) : x(x), y(y) {
	}

	int getX() const { return x; }
	int getY() const { return y; }

private:
	int x;
	int y;
};

constexpr int mouseEventId = 3;

// A free function that will be added as listener later.
// argumentAdapter works on all types of callables, include but not limited to,
// lambda, functor object, std::function, free function, etc.
void tutorialArgumentAdapterFreeFunction(const MouseEvent & e)
{
	std::cout << "Received MouseEvent in free function, x=" << e.getX() << " y=" << e.getY() << std::endl;
}

void main()
{
	std::cout << std::endl << "ArgumentAdapter tutorial 1, basic" << std::endl;

	eventpp::EventDispatcher<int, void (const Event &)> eventDispatcher;

	// callback 1 -- lambda, or any functor object

	// This can't compile because a 'const Event &' can be passed to 'const MouseEvent &'
	//eventDispatcher.appendListener(mouseEventId, [](const MouseEvent & e) {});

	// This compiles. eventpp::argumentAdapter creates a functor object that static_cast 
	// 'const Event &' to 'const MouseEvent &' automatically.
	// Note we need to pass the function type to eventpp::argumentAdapter because the lambda
	// doesn't have any function type information and eventpp::argumentAdapter can't deduce
	// the type. This rule also applies to other functor object.
	eventDispatcher.appendListener(
		mouseEventId,
		eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
			std::cout << "Received MouseEvent in lambda, x=" << e.getX() << " y=" << e.getY() << std::endl;
		})
	);

	// callback 2 -- std::function
	// We don't need to pass the function type to eventpp::argumentAdapter because it can
	// deduce the type from the std::function
	eventDispatcher.appendListener(
		mouseEventId,
		eventpp::argumentAdapter(std::function<void(const MouseEvent &)>([](const MouseEvent & e) {
			std::cout << "Received MouseEvent in std::function, x=" << e.getX() << " y=" << e.getY() << std::endl;
		}))
	);

	// callback 3 -- free function
	// We don't need to pass the function type to eventpp::argumentAdapter because it can
	// deduce the type from the free function
	eventDispatcher.appendListener(
		mouseEventId,
		eventpp::argumentAdapter(tutorialArgumentAdapterFreeFunction)
	);

	eventDispatcher.dispatch(mouseEventId, MouseEvent(3, 5));
}