Slot Arguments (Beginner)
插槽的参数(初级)
Signals can propagate arguments to each of the slots they call.For instance, a signal that propagates mouse motion events mightwant to pass along the new mouse coordinates and whether the mousebuttons are pressed.
信号可以向它们调用的每个插槽传递参数。例如,一个传递鼠标移动事件的信号可能要传入新的鼠标坐标以及是否按了鼠标键。
As an example, we'll create a signal that passes twofloat
arguments to its slots. Then we'll create a fewslots that print the results of various arithmetic operations onthese values.
作为一个例子,我们将创建一个信号,它将传入两个float
参数到它的插槽。然后我们将创建几个插槽,它们将打印对这两个参数进行算术运算的各种结果。
void print_sum(float x, float y)
{
std::cout << "The sum is " << x+y << std::endl;
}
void print_product(float x, float y)
{
std::cout << "The product is " << x*y << std::endl;
}
void print_difference(float x, float y)
{
std::cout << "The difference is " << x-y << std::endl;
}
void print_quotient(float x, float y)
{
std::cout << "The quotient is " << x/y << std::endl;
}
This program will print out the following:
该程序将打印输出如下:
The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667
So any values that are given to sig
when it iscalled like a function are passed to each of the slots. We have todeclare the types of these values up front when we create thesignal. The type boost::signal<void (float,float)>
means that the signal has a void
return value and takes two float
values. Any slotconnected to sig
must therefore be able to take twofloat
values.
当像函数一样调用 sig
时,输入它的任何值都传给了每一个插槽。创建信号时,我们必须预先声明这些值的类型。类型 boost::signal<void (float,float)>
表明信号具有 void
返回值并接受两个 float
值。因此任何连接到sig
的插槽都必须能够接受两个float
值。
Signal Return Values (Advanced)
信号返回值(高级)
Just as slots can receive arguments, they can also returnvalues. These values can then be returned back to the caller of thesignal through a combiner. The combiner is a mechanismthat can take the results of calling slots (there many be noresults or a hundred; we don't know until the program runs) andcoalesces them into a single result to be returned to the caller.The single result is often a simple function of the results of theslot calls: the result of the last slot call, the maximum valuereturned by any slot, or a container of all of the results are somepossibilities.
正如插槽可以接收参数,它们也可以返回值。然后这些值可以通过合并器(combiner)返回给信号的调用者。合并器是这样一种工具,它接收插槽调用的结果(可能没有结果,也可能有100个结果;程序运行时才知道),并且把它们合并成单一的结果返回给调用者。该单一的结果往往是插槽调用结果的一个简单函数,可能是:最后的插槽调用的结果、所有插槽返回值的最大值,或包含所有结果的容器。
We can modify our previous arithmetic operations exampleslightly so that the slots all return the results of computing theproduct, quotient, sum, or difference. Then the signal itself canreturn a value based on these results to be printed:
我们可以稍微修改前面的算术运算的例子,使插槽分别返回加减乘除的计算结果。然后信号本身就可以根据这些结果返回一个值,并打印出来。
This example program will output 2
. This is because thedefault behavior of a signal that has a return type(float
, the first template argument given to theboost::signal
class template) is to call all slots andthen return the result returned by the last slot called. Thisbehavior is admittedly silly for this example, because slots haveno side effects and the result is the last slot connect.
该例程将输出 2
。这是因为具有返回类型(float
,即输入 boost::signal
类模板的第一个模板参数)的信号的默认行为是,调用所有的插槽,然后返回最后一个被调用插槽的结果。对本例来说,该行为确实有点傻,因为这些插槽没有副作用并且结果就是最后的插槽连接。
A more interesting signal result would be the maximum of thevalues returned by any slot. To do this, we create a customcombiner that looks like this:
一个更有意思的信号结果是,求所有插槽返回值的最大值。为了做到这一点,我们创建了一个自定义合并器,看起来像这样:
template<typename T>
struct maximum
{
typedef T result_type;
template<typename InputIterator>
T operator()(InputIterator first, InputIterator last) const
{
// If there are no slots to call, just return the
// default-constructed value
if (first == last)
return T();
T max_value = *first++;
while (first != last) {
if (max_value < *first)
max_value = *first;
++first;
}
return max_value;
}
};
The maximum
class template acts as a functionobject. Its result type is given by its template parameter, andthis is the type it expects to be computing the maximum based on(e.g., maximum<float>
would find the maximumfloat
in a sequence of float
s). When amaximum
object is invoked, it is given an inputiterator sequence [first, last)
that includes theresults of calling all of the slots. maximum
uses thisinput iterator sequence to calculate the maximum element, andreturns that maximum value.
maximum
类模板就像一个函数对象。它的结果类型由其模板参数给出,并且它正是基于该类型计算最大值(例如,maximum<float>
将在一系列 float
中查找最大的 float
)。当调用maximum
对象时,将给出一个输入迭代器序列[first, last)
,其中包含了所有插槽调用的结果。maximum
利用该输入迭代器序列来计算最大元素,并返回那个最大值。
We actually use this new function object type by installing itas a combiner for our signal. The combiner template argumentfollows the signal's calling signature:
我们要把这个新的函数对象作为合并器安装到我们的信号,才能实际使用它。合并器模板参数跟在信号的调用签名式之后。
Now we can connect slots that perform arithmetic functions anduse the signal:
现在我们可以连接执行算术功能的插槽并使用信号了:
sig.connect
("ient);
sig.connect
(&product);
sig.connect
(&sum);
sig.connect
(&difference);
std::cout << sig(5, 3) << std::endl;
The output of this program will be 15
, becauseregardless of the order in which the slots are connected, the productof 5 and 3 will be larger than the quotient, sum, ordifference.
该程序的输出为 15
,因为不管插槽的连接次序如何,5 和 3 的乘积将大于商、和,或差。
In other cases we might want to return all of the valuescomputed by the slots together, in one large data structure. Thisis easily done with a different combiner:
在其他情况下,我们可能要同时返回插槽计算的所有值,如保存在一个大型的数据结构中。这可以用一个不同的合并器来轻松完成:
template<typename Container>
struct aggregate_values
{
typedef Container result_type;
template<typename InputIterator>
Container operator()(InputIterator first, InputIterator last) const
{
return Container(first, last);
}
};
Again, we can create a signal with this new combiner:
我们再次用这个新的合并器创建信号:
The output of this program will contain 15, 8, 1.6667, and 2. Itis interesting here thatthe first template argument for the signal
class,float
, is not actually the return type of the signal.Instead, it is the return type used by the connected slots and willalso be the value_type
of the input iterators passedto the combiner. The combiner itself is a function object and itsresult_type
member type becomes the return type of thesignal.
该程序的输出将包含 15、8、1.6667,和 2。这里有趣的是,signal
类的第一个模板参数,float
,竟然不是信号的返回类型。相反,该参数是所连接插槽的返回类型,并且它也是传入合并器的输入迭代器的value_type
。合并器本身是个函数对象,并且它的result_type
成员类型将成为信号的返回类型。
The input iterators passed to the combiner transform dereferenceoperations into slot calls. Combiners therefore have the option toinvoke only some slots until some particular criterion is met. Forinstance, in a distributed computing system, the combiner may askeach remote system whether it will handle the request. Only oneremote system needs to handle a particular request, so after aremote system accepts the work we do not want to ask any otherremote systems to perform the same task. Such a combiner need onlycheck the value returned when dereferencing the iterator, andreturn when the value is acceptable. The following combiner returnsthe first non-NULL pointer to a FulfilledRequest
datastructure, without asking any later slots to fulfill therequest:
传给合并器的输入迭代器会将解引用操作转换为插槽调用。因此合并器可选择仅调用某些符合特定条件的插槽。例如,在分布计算系统中,合并器可能会询问每个远程系统能否处理请求。对于一个特定请求,仅需一个远程系统进行处理,因此当一个远程系统接受该工作后,我们将不再要求任何其他远程系统来做同一个任务。这样一个合并器只需检查迭代器解引用的返回值,并当该值可以接受时就返回。以下的合并器返回第一个指向FulfilledRequest
数据结构的非空指针,而不必要求任何以后的插槽来完成请求:
struct DistributeRequest {
typedef FulfilledRequest* result_type;
template<typename InputIterator>
result_type operator()(InputIterator first, InputIterator last) const
{
while (first != last) {
if (result_type fulfilled = *first)
return fulfilled;
++first;
}
return 0;
}
};