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;
}
};