|
|
@@ -19,14 +19,14 @@
|
|
|
|
|
|
# Introduction
|
|
|
|
|
|
-Signals are usually a core part of games and software architectures in
|
|
|
-general.<br/>
|
|
|
-Roughly speaking, they help to decouple the various parts of a system while
|
|
|
-allowing them to communicate with each other somehow.
|
|
|
+Signals are more often than not a core part of games and software architectures
|
|
|
+in general.<br/>
|
|
|
+They help to decouple the various parts of a system while allowing them to
|
|
|
+communicate with each other somehow.
|
|
|
|
|
|
-The so called _modern C++_ comes with a tool that can be useful in these terms,
|
|
|
+The so called _modern C++_ comes with a tool that can be useful in this regard,
|
|
|
the `std::function`. As an example, it can be used to create delegates.<br/>
|
|
|
-However, there is no guarantee that an `std::function` does not perform
|
|
|
+However, there is no guarantee that an `std::function` doesn't perform
|
|
|
allocations under the hood and this could be problematic sometimes. Furthermore,
|
|
|
it solves a problem but may not adapt well to other requirements that may arise
|
|
|
from time to time.
|
|
|
@@ -38,8 +38,8 @@ lightweight classes to solve the same and many other problems.
|
|
|
# Delegate
|
|
|
|
|
|
A delegate can be used as a general purpose invoker with no memory overhead for
|
|
|
-free functions and members provided along with an instance on which to invoke
|
|
|
-them.<br/>
|
|
|
+free functions and member functions provided along with an instance on which to
|
|
|
+invoke them.<br/>
|
|
|
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
|
|
|
expect to use it whenever an `std::function` fits well. That said, it's most
|
|
|
likely even a better fit than an `std::function` in a lot of cases, so expect to
|
|
|
@@ -52,15 +52,13 @@ delegates:
|
|
|
entt::delegate<int(int)> delegate{};
|
|
|
```
|
|
|
|
|
|
-All what is needed to create an instance is to specify the type of the function
|
|
|
-the delegate will _contain_, that is the signature of the free function or the
|
|
|
-member one wants to assign to it.
|
|
|
+What is needed to create an instance is to specify the type of the function the
|
|
|
+delegate _accepts_, that is the signature of the functions it models.<br/>
|
|
|
+However, attempting to use an empty delegate by invoking its function call
|
|
|
+operator results in undefined behavior or most likely a crash.
|
|
|
|
|
|
-Attempting to use an empty delegate by invoking its function call operator
|
|
|
-results in undefined behavior or most likely a crash. Before to use a delegate,
|
|
|
-it must be initialized.<br/>
|
|
|
-There exists a bunch of overloads of the `connect` member function to do that.
|
|
|
-As an example of use:
|
|
|
+There exist a few overloads of the `connect` member function to initialize a
|
|
|
+delegate:
|
|
|
|
|
|
```cpp
|
|
|
int f(int i) { return i; }
|
|
|
@@ -77,7 +75,7 @@ my_struct instance;
|
|
|
delegate.connect<&my_struct::f>(instance);
|
|
|
```
|
|
|
|
|
|
-The delegate class accepts also data members, if needed. In this case, the
|
|
|
+The delegate class also accepts data members, if needed. In this case, the
|
|
|
function type of the delegate is such that the parameter list is empty and the
|
|
|
value of the data member is at least convertible to the return type.
|
|
|
|
|
|
@@ -94,14 +92,11 @@ delegate.connect<&g>(c);
|
|
|
delegate(42);
|
|
|
```
|
|
|
|
|
|
-The function `g` will be invoked with a reference to `c` and `42`. However, the
|
|
|
+The function `g` is invoked with a reference to `c` and `42`. However, the
|
|
|
function type of the delegate is still `void(int)`. This is also the signature
|
|
|
-of its function call operator.
|
|
|
-
|
|
|
-Another interesting aspect of the delegate class is that it accepts also
|
|
|
-functions with a list of parameters that is shorter than that of the function
|
|
|
-type used to specialize the delegate itself.<br/>
|
|
|
-The following code is therefore perfectly valid:
|
|
|
+of its function call operator.<br/>
|
|
|
+Another interesting aspect of the delegate class is that it accepts functions
|
|
|
+with a list of parameters that is shorter than that of its function type:
|
|
|
|
|
|
```cpp
|
|
|
void g() { /* ... */ }
|
|
|
@@ -140,7 +135,7 @@ already shown in the examples above:
|
|
|
auto ret = delegate(42);
|
|
|
```
|
|
|
|
|
|
-In all cases, the listeners don't have to strictly follow the signature of the
|
|
|
+In all cases, listeners don't have to strictly follow the signature of the
|
|
|
delegate. As long as a listener can be invoked with the given arguments to yield
|
|
|
a result that is convertible to the given result type, everything works just
|
|
|
fine.
|
|
|
@@ -158,7 +153,7 @@ my_struct instance;
|
|
|
delegate(instance, 42);
|
|
|
```
|
|
|
|
|
|
-In this case, it's not possible to deduce the function type since the first
|
|
|
+In this case, it's not possible to _deduce_ the function type since the first
|
|
|
argument doesn't necessarily have to be a reference (for example, it can be a
|
|
|
pointer, as well as a const reference).<br/>
|
|
|
Therefore, the function type must be declared explicitly for unbound members.
|
|
|
@@ -166,10 +161,9 @@ Therefore, the function type must be declared explicitly for unbound members.
|
|
|
## Runtime arguments
|
|
|
|
|
|
The `delegate` class is meant to be used primarily with template arguments.
|
|
|
-However, as a consequence of its design, it can also offer minimal support for
|
|
|
+However, as a consequence of its design, it also offers minimal support for
|
|
|
runtime arguments.<br/>
|
|
|
-When used in this modality, some features aren't supported though. In
|
|
|
-particular:
|
|
|
+When used like this, some features aren't supported though. In particular:
|
|
|
|
|
|
* Curried functions aren't accepted.
|
|
|
* Functions with an argument list that differs from that of the delegate aren't
|
|
|
@@ -248,16 +242,17 @@ Signals make use of delegates internally and therefore they undergo the same
|
|
|
rules and offer similar functionalities. It may be a good idea to consult the
|
|
|
documentation of the `delegate` class for further information.
|
|
|
|
|
|
-A signal handler can be used as a private data member without exposing any
|
|
|
-_publish_ functionality to the clients of a class. The basic idea is to impose a
|
|
|
-clear separation between the signal itself and the `sink` class, that is a tool
|
|
|
-to be used to connect and disconnect listeners on the fly.
|
|
|
+A signal handler is can be used as a private data member without exposing any
|
|
|
+_publish_ functionality to the clients of a class.<br/>
|
|
|
+The basic idea is to impose a clear separation between the signal itself and the
|
|
|
+`sink` class, that is a tool to be used to connect and disconnect listeners on
|
|
|
+the fly.
|
|
|
|
|
|
The API of a signal handler is straightforward. If a collector is supplied to
|
|
|
-the signal when something is published, all the values returned by the listeners
|
|
|
-can be literally _collected_ and used later by the caller. Otherwise, the class
|
|
|
+the signal when something is published, all the values returned by its listeners
|
|
|
+are literally _collected_ and used later by the caller. Otherwise, the class
|
|
|
works just like a plain signal that emits events from time to time.<br/>
|
|
|
-To create instances of signal handlers it is sufficient to provide the type of
|
|
|
+To create instances of signal handlers it's sufficient to provide the type of
|
|
|
function to which they refer:
|
|
|
|
|
|
```cpp
|
|
|
@@ -301,13 +296,13 @@ sink.disconnect(instance);
|
|
|
sink.disconnect();
|
|
|
```
|
|
|
|
|
|
-As shown above, the listeners don't have to strictly follow the signature of the
|
|
|
+As shown above, listeners don't have to strictly follow the signature of the
|
|
|
signal. As long as a listener can be invoked with the given arguments to yield a
|
|
|
result that is convertible to the given return type, everything works just
|
|
|
fine.<br/>
|
|
|
-It's also possible to connect a listener before other listeners already
|
|
|
-contained by the signal. The `before` function returns a `sink` object correctly
|
|
|
-initialized for the purpose that can be used to connect one or more listeners in
|
|
|
+It's also possible to connect a listener before other elements already contained
|
|
|
+by the signal. The `before` function returns a `sink` object that is correctly
|
|
|
+initialized for the purpose and can be used to connect one or more listeners in
|
|
|
order and in the desired position:
|
|
|
|
|
|
```cpp
|
|
|
@@ -316,20 +311,19 @@ sink.before<&foo>().connect<&listener::bar>(instance);
|
|
|
|
|
|
In all cases, the `connect` member function returns by default a `connection`
|
|
|
object to be used as an alternative to break a connection by means of its
|
|
|
-`release` member function. A `scoped_connection` can also be created from a
|
|
|
-connection. In this case, the link is broken automatically as soon as the object
|
|
|
-goes out of scope.
|
|
|
+`release` member function.<br/>
|
|
|
+A `scoped_connection` can also be created from a connection. In this case, the
|
|
|
+link is broken automatically as soon as the object goes out of scope.
|
|
|
|
|
|
Once listeners are attached (or even if there are no listeners at all), events
|
|
|
-and data in general can be published through a signal by means of the `publish`
|
|
|
+and data in general are published through a signal by means of the `publish`
|
|
|
member function:
|
|
|
|
|
|
```cpp
|
|
|
signal.publish(42, 'c');
|
|
|
```
|
|
|
|
|
|
-To collect data, the `collect` member function should be used instead. Below is
|
|
|
-a minimal example to show how to use it:
|
|
|
+To collect data, the `collect` member function is used instead:
|
|
|
|
|
|
```cpp
|
|
|
int f() { return 0; }
|
|
|
@@ -529,8 +523,8 @@ emitter.erase<my_event>();
|
|
|
emitter.clear()
|
|
|
```
|
|
|
|
|
|
-To send an event to the listener registered on a given type, the `publish` is
|
|
|
-the way to go:
|
|
|
+To send an event to the listener registered on a given type, the `publish`
|
|
|
+function is the way to go:
|
|
|
|
|
|
```cpp
|
|
|
struct my_event { int i; };
|