青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Boost.Singals 教程

Posted on 2008-07-04 13:23 RichardHe 閱讀(942) 評論(0)  編輯 收藏 引用 所屬分類: [轉]
來自http://m.shnenglu.com/jinq0123/archive/2008/06/30/boostsignalstutorial.html
Boost c++ libraries Home Libraries People FAQ More

PrevUpHomeNext

術語表

英文 中文 注釋
block 阻塞  
combiner 合并器  
compatibility form 兼容形式  
connect 連接  
connection 連接  
disconnect 斷開  
first-in first-out (FIFO) 先進先出(FIFO)  
preferred form 首選形式  
scoped 域內的 作用域內的
signal 信號  
Signals library 信號庫  
slot 插槽  

How to Read this Tutorial

如何閱讀本教程

This tutorial is not meant to be read linearly. Its top-levelstructure roughly separates different concepts in the library(e.g., handling calling multiple slots, passing values to and fromslots) and in each of these concepts the basic ideas are presentedfirst and then more complex uses of the library are describedlater. Each of the sections is marked Beginner,Intermediate, or Advanced to help guide thereader. The Beginner sections include information that alllibrary users should know; one can make good use of the Signalslibrary after having read only the Beginner sections. TheIntermediate sections build on the Beginnersections with slightly more complex uses of the library. Finally,the Advanced sections detail very advanced uses of theSignals library, that often require a solid working knowledge ofthe Beginner and Intermediate topics; most userswill not need to read the Advanced sections.

本教程不是用來線性閱讀的。其頂層結構大致按庫中不同的概念劃分,(如處理調用多個插槽、傳值到插槽及回傳),并且在每一個這些概念中,首先介紹其基本思想,然后說明庫較復雜的使用。每個部分都標注了初級中級,或高級,以幫助指導讀者。初級部分包括庫的所有使用者都該了解的信息;只要閱讀了初級部分,就可以很好地使用信號庫。中級部分建立在初級部分之上,是庫的稍復雜的使用。最后,高級部分詳述了信號庫很高級的應用,這往往需要對初級中級內容扎實的實踐經驗;大多數用戶無需閱讀高級部分

Compatibility Note

對兼容性的注釋

Boost.Signals has two syntactical forms: the preferred form andthe compatibility form. The preferred form fits more closely with theC++ language and reduces the number of separate template parametersthat need to be considered, often improving readability; however, thepreferred form is not supported on all platforms due to compilerbugs. The compatible form will work on all compilers supported byBoost.Signals. Consult the table below to determine which syntacticform to use for your compiler. Users of Boost.Function, please notethat the preferred syntactic form in Signals is equivalent to that ofFunction's preferred syntactic form.

Boost.Signals 有兩種句法形式:首選形式(preferred form)和兼容形式(compatibility form)。首選形式能更緊密地適合C++語言,并減少需要考慮的獨立模板參數的個數,往往能提高可讀性;然而,由于編譯器的錯誤,首選形式并非所有平臺 都支持。兼容形式可工作于 Boost.Signals 支持的所有編譯器。參考下表,以確定為你的編譯器使用哪種句法形式。Boost.Function 的用戶請注意,Signals 中的首選句法形式等效于 Function 的首選句法形式。

If your compiler does not appear in this list, please try thepreferred syntax and report your results to the Boost list so thatwe can keep this table up-to-date.

如果你的編譯器不在這個清單上,請試用首選句法并向Boost列表報告你的結果,以使我們能保持更新該表。

Preferred syntax
首選句法
Portable syntax
兼容句法
           
  • GNU C++ 2.95.x, 3.0.x, 3.1.x

  • Comeau C++ 4.2.45.2

  • SGI MIPSpro 7.3.0

  • Intel C++ 5.0, 6.0

  • Compaq's cxx 6.2

  • Microsoft Visual C++ 7.1

         
           
  • Any compiler supporting the preferred syntax
    支持首選句法的任意編譯器

  • Microsoft Visual C++ 6.0, 7.0

  • Borland C++ 5.5.1

  • Sun WorkShop 6 update 2 C++ 5.3

  • Metrowerks CodeWarrior 8.1

         

Hello, World! (Beginner)

Hello, World! (初級)

The following example writes "Hello, World!" using signals andslots. First, we create a signal sig, a signal thattakes no arguments and has a void return value. Next, we connectthe hello function object to the signal using theconnect method. Finally, use the signalsig like a function to call the slots, which in turnsinvokes HelloWorld::operator() to print "Hello,World!".

下例將使用信號和插槽寫出“Hello, World!”。首先,我們創建信號 sig,該信號無參數并且返回值為空。接著,我們使用 connect 方法將 hello函數對象連接到信號。最后,像函數一樣使用信號sig來調用插槽,它將轉而調用 HelloWorld::operator()打印“Hello, World!”。

Preferred syntaxPortable syntax
struct HelloWorld 
{
  void operator()() const
  {
    std::cout << "Hello, World!" << std::endl;
  }
};

// ...

// Signal with no arguments and a void return value
boost::signal<void ()> sig;

// Connect a HelloWorld slot
HelloWorld hello;
sig.connect(hello);

// Call all of the slots
sig();
struct HelloWorld 
{
  void operator()() const
  {
    std::cout << "Hello, World!" << std::endl;
  }
};

// ...

// Signal with no arguments and a void return value
boost::signal0<void> sig;

// Connect a HelloWorld slot
HelloWorld hello;
sig.connect(hello);

// Call all of the slots
sig();

Calling multiple slots

調用多個插槽

Connecting multiple slots (Beginner)

連接多個插槽(初級)

Calling a single slot from a signal isn't very interesting, sowe can make the Hello, World program more interesting by splittingthe work of printing "Hello, World!" into two completely separateslots. The first slot will print "Hello" and may look likethis:

從信號調用單個插槽不是很有意思,因此我們將打印“Hello, World!”的工作拆分到兩個完全獨立的插槽,讓 Hello, World 程序更有趣點。第一個插槽將打印“Hello”,可能看起來像這樣:

struct Hello 
{
  void operator()() const
  {
    std::cout << "Hello";
  }
};

The second slot will print ", World!" and a newline, to completethe program. The second slot may look like this:

第二個插槽將打印“, World!”并回車以完成該程序。第二個插槽可能看起來像這樣:

struct World
{
  void operator()() const
  {
    std::cout << ", World!" << std::endl;
  }
};

Like in our previous example, we can create a signalsig that takes no arguments and has avoid return value. This time, we connect both ahello and a world slot to the samesignal, and when we call the signal both slots will be called.

就像我們的上個例子,我們創建信號sig,它沒有參數并且返回值為void。這次,我們將helloworld插槽都連接到同一個信號,當我們調用該信號,兩個插槽都將會被調用。

Preferred syntaxPortable syntax
boost::signal<void ()> sig;

sig.connect(Hello());
sig.connect(World());

sig();
boost::signal0<void> sig;

sig.connect(Hello());
sig.connect(World());

sig();

By default, slots are called in first-in first-out (FIFO) order,so the output of this program will be as expected:

默認情況下,插槽以先進先出(FIFO)的次序被調用,因此該程序的輸出應該是:

Hello, World!

Ordering slot call groups (Intermediate)

插槽調用組排序(中級)

Slots are free to have side effects, and that can mean that someslots will have to be called before others even if they are not connected in that order. The Boost.Signalslibrary allows slots to be placed into groups that are ordered insome way. For our Hello, World program, we want "Hello" to beprinted before ", World!", so we put "Hello" into a group that mustbe executed before the group that ", World!" is in. To do this, wecan supply an extra parameter at the beginning of theconnect call that specifies the group. Group valuesare, by default, ints, and are ordered by the integer< relation. Here's how we construct Hello, World:

插槽可以隨意具有副作用,即某些插槽必須在另一些之前調用,即使它們不是按那個次序連接的。Boost.Signals 庫允許插槽被置于按某種方式排序的編組中。對于我們的 Hello, World 程序,我們要“Hello”在“, World!”之前打印,所以我們將“Hello”放入一個組,該組將在“, World!”所在組之前執行。為了做到這一點,我們可以在connect調用的頭部提供一個額外的參數,以指定該組。編組的值默認為int,并按整型的 < 關系排序。我們這樣構造 Hello, World:

Preferred syntaxPortable syntax
boost::signal<void ()> sig;
sig.connect(1, World());
sig.connect(0, Hello());
sig();
boost::signal0<void> sig;
sig.connect(1, World());
sig.connect(0, Hello());
sig();

This program will correctly print "Hello, World!", because theHello object is in group 0, which precedes group 1 wherethe World object resides. The groupparameter is, in fact, optional. We omitted it in the first Hello,World example because it was unnecessary when all of the slots areindependent. So what happens if we mix calls to connect that use thegroup parameter and those that don't? The "unnamed" slots (i.e., thosethat have been connected without specifying a group name) can beplaced at the front or back of the slot list (by passingboost::signals::at_front or boost::signals::at_backas the last parameter to connect, respectively), and defaults to the end of the list. Whena group is specified, the final parameter describes where the slotwill be placed within the group ordering. If we add a new slotto our example like this:

該程序將正確打印出“Hello, World!”,因為Hello 對象在組 0,它在World 對象所在的組 1 之前。編組參數實際上是可選的。在第一個 Hello World 例子中我們省略了它,因為當所有的插槽都獨立時,編組是不必要的。那么,如果我們混合調用使用和不使用編組參數的連接會怎樣?“未命名”插槽(即那些連接 時未指定組名的插槽)可置于插槽鏈表的頭部或尾部(通過向connect分別傳入boost::signals::at_frontboost::signals::at_back作為最后的參數),而默認為鏈表的結尾。當指定了編組時,最后的參數描述的是插槽在組內的次序。如果我們如下向我們的例子添加新的插槽:

struct GoodMorning
{
  void operator()() const
  {
    std::cout << "... and good morning!" << std::endl;
  }
};

sig.connect(GoodMorning());

... we will get the result we wanted:

……我們將得到我們想要的結果:

Hello, World!
... and good morning!

Passing values to and from slots

傳值到插槽及回傳

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;
}
Preferred syntaxPortable syntax
boost::signal<void (float, float)> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);
boost::signal2<void, float, float> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

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 voidreturn 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:

我們可以稍微修改前面的算術運算的例子,使插槽分別返回加減乘除的計算結果。然后信號本身就可以根據這些結果返回一個值,并打印出來。

Preferred syntaxPortable syntax
float product(float x, float y) { return x*y; }
float quotient(float x, float y) { return x/y; }
float sum(float x, float y) { return x+y; }
float difference(float x, float y) { return x-y; }

boost::signal<float (float x, float y)> sig;

sig.connect(&product);
sig.connect(&quotient);
sig.connect(&sum);
sig.connect(&difference);

std::cout << sig(5, 3) << std::endl;
float product(float x, float y) { return x*y; }
float quotient(float x, float y) { return x/y; }
float sum(float x, float y) { return x+y; }
float difference(float x, float y) { return x-y; }

boost::signal2<float, float, float> sig;

sig.connect(&product);
sig.connect(&quotient);
sig.connect(&sum);
sig.connect(&difference);

std::cout << sig(5, 3) << std::endl;

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 floats). 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:

我們要把這個新的函數對象作為合并器安裝到我們的信號,才能實際使用它。合并器模板參數跟在信號的調用簽名式之后。

Preferred syntaxPortable syntax
boost::signal<float (float x, float y), 
              maximum<float> > sig;
boost::signal2<float, float, float, 
               maximum<float> > sig;

Now we can connect slots that perform arithmetic functions anduse the signal:

現在我們可以連接執行算術功能的插槽并使用信號了:

sig.connect(&quotient);
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:

我們再次用這個新的合并器創建信號:

Preferred syntaxPortable syntax
boost::signal<float (float, float), 
    aggregate_values<std::vector<float> > > sig;

sig.connect(&quotient);
sig.connect(&product);
sig.connect(&sum);
sig.connect(&difference);

std::vector<float> results = sig(5, 3);
std::copy(results.begin(), results.end(),
    std::ostream_iterator<float>(cout, " "));
boost::signal2<float, float, float,
    aggregate_values<std::vector<float> > > sig;

sig.connect(&quotient);
sig.connect(&product);
sig.connect(&sum);
sig.connect(&difference);

std::vector<float> results = sig(5, 3);
std::copy(results.begin(), results.end(),
    std::ostream_iterator<float>(cout, " "));

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

Connection Management

連接管理

Disconnecting Slots (Beginner)

斷開插槽(初級)

Slots aren't expected to exist indefinately after they areconnected. Often slots are only used to receive a few events andare then disconnected, and the programmer needs control to decidewhen a slot should no longer be connected.

插槽不要求在它們被連接后無限期地存在。往往插槽只是用來接收一些事件然后斷開,而程序員需要控制決定何時插槽不應該再繼續連接。

The entry point for managing connections explicitly is theboost::signals::connection class. Theconnection class uniquely represents the connectionbetween a particular signal and a particular slot. Theconnected() method checks if the signal and slot arestill connected, and the disconnect() methoddisconnects the signal and slot if they are connected before it iscalled. Each call to the signal's connect() methodreturns a connection object, which can be used to determine if theconnection still exists or to disconnect the signal and slot.

顯式管理連接的入口點是boost::signals::connection 類。connection 類唯一代表了特定信號與特定插槽之間的連接。connected() 方法檢查信號與插槽是否仍保持連接,如果信號與插槽是連接著的,disconnect() 方法斷開它們的連接。每次調用信號的 connect() 方法,就返回一個連接對象,該對象用于確定連接是否仍然存在,或者用于斷開信號和插槽。

boost::signals::connection c = sig.connect(HelloWorld());
if (c.connected()) {
// c is still connected to the signal
  sig(); // Prints "Hello, World!"
}

c.disconnect(); // Disconnect the HelloWorld object
assert(!c.connected()); c isn't connected any more

sig(); // Does nothing: there are no connected slots

Blocking Slots (Beginner)

阻塞插槽(初級)

Slots can be temporarily "blocked", meaning that they will beignored when the signal is invoked but have not been disconnected. Theblock member functiontemporarily blocks a slot, which can be unblocked viaunblock. Here is an example ofblocking/unblocking slots:

插槽可以被臨時“阻塞”,即當信號被調用時,這些插槽將被忽略,但并沒有被斷開。block 成員函數臨時地阻塞一個插槽,可通過 unblock解除阻塞。這是一個阻塞/開啟插槽的例子:

boost::signals::connection c = sig.connect(HelloWorld());
sig(); // Prints "Hello, World!"

c.block(); // block the slot
assert(c.blocked());
sig(); // No output: the slot is blocked

c.unblock(); // unblock the slot
sig(); // Prints "Hello, World!"

Scoped connections (Intermediate)

域內連接(中級)

The boost::signals::scoped_connection classreferences a signal/slot connection that will be disconnected whenthe scoped_connection class goes out of scope. Thisability is useful when a connection need only be temporary,e.g.,

boost::signals::scoped_connection 類引用了一個信號/插槽的連接,當scoped_connection類出作用域時,該連接將會被斷開。當僅需臨時連接時,該功能很有用,如:

{
  boost::signals::scoped_connection c = sig.connect(ShortLived());
  sig(); // will call ShortLived function object
}
sig(); // ShortLived function object no longer connected to sig

Disconnecting equivalent slots (Intermediate)

斷開等價的插槽(中級)

One can disconnect slots that are equivalent to a given functionobject using a form of thedisconnect method, so long asthe type of the function object has an accessible ==operator. For instance:

你可以使用disconnect方法斷開與給定函數對象等價的多個插槽,只要該函數對象的類型具有可訪問的==運算符。例如:

Preferred syntaxPortable syntax
void foo();
void bar();

signal<void()> sig;

sig.connect(&foo);
sig.connect(&bar);

// disconnects foo, but not bar
sig.disconnect(&foo);
void foo();
void bar();

signal0<void> sig;

sig.connect(&foo);
sig.connect(&bar);

// disconnects foo, but not bar
sig.disconnect(&foo);

Automatic connection management (Intermediate)

自動連接管理(中級)

Boost.Signals can automatically track the lifetime of objectsinvolved in signal/slot connections, including automaticdisconnection of slots when objects involved in the slot call aredestroyed. For instance, consider a simple news delivery service,where clients connect to a news provider that then sends news toall connected clients as information arrives. The news deliveryservice may be constructed like this:

Boost.Signals 能自動跟蹤信號/插槽連接中所涉及對象的生命期,包括當插槽調用中涉及的對象銷毀時自動斷開插槽。例如,考慮一個簡單的新聞發送服務,其中客戶會連接到新 聞提供者,而新聞提供者一有信息到達,就發送新聞到所有連接的客戶。該新聞發送服務可能像這樣構造:

Preferred syntaxPortable syntax
class NewsItem { /* ... */ };

boost::signal<void (const NewsItem&)> deliverNews;
class NewsItem { /* ... */ };

boost::signal1<void, const NewsItem&> deliverNews;

Clients that wish to receive news updates need only connect afunction object that can receive news items to thedeliverNews signal. For instance, we may have aspecial message area in our application specifically for news,e.g.,:

希望接收新聞更新的客戶只需連接一個函數對象,該對象可以接收傳給deliverNews信號的新聞條目,例如:

struct NewsMessageArea : public MessageArea
{
public:
  // ...

  void displayNews(const NewsItem& news) const
  {
    messageText = news.text();
    update();
  }
};

// ...
NewsMessageArea newsMessageArea = new NewsMessageArea(/* ... */);
// ...
deliverNews.connect(boost::bind(&NewsMessageArea::displayNews,
                                newsMessageArea, _1));

However, what if the user closes the news message area,destroying the newsMessageArea object thatdeliverNews knows about? Most likely, a segmentationfault will occur. However, with Boost.Signals one need only makeNewsMessageArea trackable, and the slotinvolving newsMessageArea will be disconnected whennewsMessageArea is destroyed. TheNewsMessageArea class is made trackable by derivingpublicly from the boost::signals::trackable class,e.g.:

不過,如果用戶關閉新聞訊息區,銷毀了 deliverNews所知的 newsMessageArea 對象,那會怎么樣?最有可能的是產生段錯誤。然而,你只需在使用 Boost.Signals 時,讓NewsMessageArea 可跟蹤(trackable),那么當 newsMessageArea 被銷毀時,調用 newsMessageArea 的插槽就會被斷開。通過公有繼承自boost::signals::trackable 類,NewsMessageArea 類就會變成可跟蹤的,例如:

struct NewsMessageArea : public MessageArea, public boost::signals::trackable
{
  // ...
};

At this time there is a significant limitation to the use oftrackable objects in making slot connections: functionobjects built using Boost.Bind are understood, such that pointersor references to trackable objects passed toboost::bind will be found and tracked.

目前,用 trackable 對象制作插槽連接有個重要的限制:它理解使用 Boost.Bind 構建的函數對象,如傳入boost::bindtrackable 對象指針或引用將會被發現和跟蹤。

Warning: User-defined function objects and functionobjects from other libraries (e.g., Boost.Function or Boost.Lambda)do not implement the required interfaces for trackableobject detection, and will silently ignore any bound trackableobjects. Future versions of the Boost libraries will addressthis limitation.

警告:用戶自定義函數對象和來自其他庫的函數對象(例如來自 Boost.Function 或 Boost.Lambda),沒有實現所要求的trackable 對象檢測接口,將會默默地忽略任何綁定的可跟蹤對象。Boost庫的未來版本將會解除該限制。

When can disconnections occur? (Intermediate)

何時斷開?(中級)

Signal/slot disconnections occur when any of these conditionsoccur:

以下任一條件發生時,信號/插槽將斷開:

  • The connection is explicitly disconnected via the connection'sdisconnect method directly, or indirectly via thesignal's disconnect method orscoped_connection's destructor.

    連接顯式斷開:直接通過連接的disconnect 方法, 或間接地通過信號的disconnect 方法或scoped_connection的析構函數。

  • A trackable object bound to the slot isdestroyed.

    銷毀綁定于插槽的 trackable 對象。

  • The signal is destroyed.

    銷毀信號。

These events can occur at any time without disrupting a signal'scalling sequence. If a signal/slot connection is disconnected atany time during a signal's calling sequence, the calling sequencewill still continue but will not invoke the disconnected slot.Additionally, a signal may be destroyed while it is in a callingsequence, and which case it will complete its slot call sequencebut may not be accessed directly.

這些事件可以發生于任何時間,而不會破壞信號的調用序列。如果信號/插槽的連接在信號調用序列的任意時刻被斷開,調用序列仍將繼續,只是不會調用被斷開的插槽。此外,信號可以在調用序列中間被銷毀,這時,它將完成其插槽調用序列,只是不可以被直接訪問。

Signals may be invoked recursively (e.g., a signal A calls aslot B that invokes signal A...). The disconnection behavior doesnot change in the recursive case, except that the slot callingsequence includes slot calls for all nested invocations of thesignal.

信號可以被遞歸調用(例如,信號A調用插槽B,而插槽B又調用信號A……)。遞歸情況下,斷開的行為不會改變,只是插槽調用序列包括所有嵌套的信號調用。

Passing slots (Intermediate)

傳遞插槽(中級)

Slots in the Boost.Signals library are created from arbitraryfunction objects, and therefore have no fixed type. However, it iscommonplace to require that slots be passed through interfaces thatcannot be templates. Slots can be passed via theslot_type for each particular signal type and anyfunction object compatible with the signature of the signal can bepassed to a slot_type parameter. For instance:

Boost.Signals 庫中的插槽可以從任意的函數對象創建,因此沒有固定的類型。不過通常要求通過不可模板化的接口傳遞插槽。對于每個特定的信號類型,都可以通過slot_type傳遞插槽,而與信號的簽名式兼容的任意函數對象,都可以傳給 slot_type 參數。例如:

Preferred syntaxPortable syntax
class Button 
{
  typedef boost::signal<void (int x, int y)> OnClick;

public:
  void doOnClick(const OnClick::slot_type& slot);

private:
  OnClick onClick;
};

void Button::doOnClick(
      const OnClick::slot_type& slot
    )
{
  onClick.connect(slot);
}

void printCoordinates(long x, long y)
{
  std::cout << "(" << x << ", " << y << ")\n";
}

void f(Button& button)
{
  button.doOnClick(&printCoordinates);
}
class Button 
{
  typedef boost::signal2<void,int,int> OnClick;

public:
  void doOnClick(const OnClick::slot_type& slot);

private:
  OnClick onClick;
};

void Button::doOnClick(
      const OnClick::slot_type& slot
    )
{
  onClick.connect(slot);
}

void printCoordinates(long x, long y)
{
  std::cout << "(" << x << ", " << y << ")\n";
}

void f(Button& button)
{
  button.doOnClick(&printCoordinates);
}

The doOnClick method is now functionally equivalentto the connect method of the onClicksignal, but the details of the doOnClick method can behidden in an implementation detail file.

doOnClick 方法現在功能上等效于onClick 信號的connect 方法,但是 doOnClick 方法的細節可以隱藏于細節實現文件中。

Example: Document-View

例子:文檔-視圖

Signals can be used to implement flexible Document-View  architectures. The document will contain a signal to which each of  the views can connect. The following Document class  defines a simple text document that supports mulitple views. Note  that it stores a single signal to which all of the views will be  connected.

 

信號可用于實現靈活的文檔-視圖(Document-View)架構。    文檔包含一個信號,而每個視圖連接該信號。    下面的 Document   類定義了一個簡單的支持多視圖的文本文檔。    注意它保存了一個單一的信號,所有視圖都連接到該信號。 

 
class Document
{
public:
    typedef boost::signal<void (bool)>  signal_t;
    typedef boost::signals::connection  connection_t;

public:
    Document()
    {}

    connection_t connect(signal_t::slot_function_type subscriber)
    {
        return m_sig.connect(subscriber);
    }

    void disconnect(connection_t subscriber)
    {
        subscriber.disconnect();
    }

    void append(const char* s)
    {
        m_text += s;
        m_sig(true);
    }

    const std::string& getText() const
    {
        return m_text;
    }

private:
    signal_t    m_sig;
    std::string m_text;
};

Next, we can define a View base class from which  views can derive. This isn't strictly required, but it keeps the  Document-View logic separate from the logic itself. Note that the  constructor just connects the view to the document and the  destructor disconnects the view.

接下來,我們可以定義視圖的基類  View。  這并非嚴格需要,但它能讓文檔-視圖的邏輯與邏輯本身分離。    注意構造函數僅僅連接視圖到文檔,而析構函數斷開視圖。 

class View
{
public:
    View(Document& m)
        : m_document(m)
    {
        m_connection = m_document.connect(boost::bind(&View::refresh, this, _1));
    }

    virtual ~View()
    {
        m_document.disconnect(m_connection);
    }

    virtual void refresh(bool bExtended) const = 0;

protected:
    Document&               m_document;

private:
    Document::connection_t  m_connection;
};
 

Finally, we can begin to define views. The  following TextView class provides a simple view of the    document text.

    

最后,我們可以開始定義視圖。    下面的 TextView  類提供了文檔文本的一個簡單視圖。 

    
class TextView : public View
{
public:
    TextView(Document& doc)
        : View(doc)
    {}

    virtual void refresh(bool bExtended) const
    {
        std::cout << "TextView: " << m_document.getText() << std::endl;
    }
};

Alternatively, we can provide a view of the document    translated into hex values using the HexView    view:

    

此外,我們可以提供文檔翻譯成16進制后的視圖,    如 HexView 視圖:   

    
class HexView : public View
{
public:
    HexView(Document& doc)
        : View(doc)
    {}

    virtual void refresh(bool bExtended) const
    {
        const std::string&  s = m_document.getText();

        std::cout << "HexView:";

        for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
            std::cout << ' ' << std::hex << static_cast<int>(*it);

        std::cout << std::endl;
    }
};

To tie the example together, here is a  simple main function that sets up two views and then    modifies the document:

    

將例子合起來,下面一個簡單的  main   函數建立了兩個視圖,然后更改文檔:   

    
int main(int argc, char* argv[])
{
    Document    doc;
    TextView    v1(doc);
    HexView     v2(doc);

    doc.append(argc == 2 ? argv[1] : "Hello world!");
    return 0;
}

The complete example source, contributed by Keith MacDonald,    is available in libs/signals/example/doc_view.cpp.

例子完整的源代碼在    libs/signals/example/doc_view.cpp,    由 Keith MacDonald 提供。

Linking against the Signals library

鏈接信號庫

Part of the Boost.Signals library is compiled into a binary  library that must be linked into your application to use  Signals. Please refer to    the Getting Started  guide. You will need to link against the boost_signals  library.

Boost.Signals 庫要編譯成二進制庫,  為使用信號庫,應用程序必須鏈接該二進制庫。  請參考    Getting Started  指導。  你將需要鏈接 boost_signals 庫。 

Last revised: January 29, 2007 at 15:05:29 -0500


PrevUpHomeNext

posts - 94, comments - 138, trackbacks - 0, articles - 94

Copyright © RichardHe

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久精品一区二区三区中文字幕| 精品99一区二区| 亚洲专区一二三| 亚洲在线一区| 欧美一区二区三区免费观看 | 亚洲成人原创| 悠悠资源网亚洲青| 日韩一区二区高清| 亚洲综合三区| 久久亚洲风情| 亚洲人午夜精品免费| 亚洲激情视频在线| 亚洲精品乱码久久久久久日本蜜臀 | 亚洲免费成人av| 亚洲女人天堂成人av在线| 久久精品视频在线播放| 欧美成人免费全部观看天天性色| 欧美精品久久久久a| 国产欧美日韩激情| 亚洲激精日韩激精欧美精品| 亚洲一级免费视频| 欧美二区在线| 亚洲一二三区在线| 欧美成人免费大片| 国产一区二区三区四区hd| 最新国产拍偷乱拍精品| 欧美一区二区三区男人的天堂| 老司机免费视频一区二区三区| 亚洲乱码视频| 美女任你摸久久| 国产欧美日韩综合精品二区| 亚洲精品一区二区三区99| 久久久噜噜噜久久中文字幕色伊伊| 亚洲激精日韩激精欧美精品| 欧美在线观看网站| 国产精品免费看久久久香蕉| 亚洲人成网站色ww在线| 久久久综合网站| 亚洲在线视频观看| 欧美日本高清一区| 亚洲国产综合91精品麻豆| 欧美在线国产| 亚洲免费在线视频| 欧美视频免费看| 日韩一级片网址| 亚洲电影在线播放| 老牛国产精品一区的观看方式| 国产美女精品免费电影| 亚洲四色影视在线观看| 最新国产成人在线观看| 久色婷婷小香蕉久久| 韩国av一区二区三区四区| 欧美一区二区三区日韩| 亚洲午夜在线| 国产精品普通话对白| 亚洲一区二区不卡免费| 一区二区欧美激情| 欧美午夜电影网| 亚洲视频在线观看一区| 99精品国产热久久91蜜凸| 欧美日韩高清一区| 亚洲图片在线| 亚洲一区二区三区四区在线观看 | 日韩视频免费观看高清在线视频| 噜噜噜噜噜久久久久久91| 欧美不卡视频| 亚洲精品国产精品国自产在线| 欧美黄色免费网站| 欧美激情一区二区三区在线视频| 亚洲精品三级| aa亚洲婷婷| 国产乱码精品一区二区三区忘忧草| 午夜精品福利视频| 性欧美xxxx大乳国产app| 国产一区二区成人久久免费影院| 久久人人爽人人| 欧美成人精品高清在线播放| 99精品欧美一区二区蜜桃免费| 亚洲精品视频免费观看| 国产精品porn| 美女诱惑一区| 欧美激情视频一区二区三区在线播放| 亚洲伦理精品| 亚洲午夜免费视频| 在线精品视频免费观看| 亚洲乱码精品一二三四区日韩在线 | 欧美一区二区三区在线| 在线观看福利一区| 亚洲免费av电影| 国产专区欧美精品| 亚洲激情第一页| 国产亚洲精品福利| 亚洲欧洲综合另类在线| 国产日韩欧美在线观看| 亚洲高清不卡av| 国产一级揄自揄精品视频| 亚洲清纯自拍| 一区二区三区在线免费播放| 亚洲乱码一区二区| 亚洲成色999久久网站| 中日韩男男gay无套| 在线日韩视频| 亚洲欧美日韩国产综合精品二区| 亚洲国产天堂久久国产91| 亚洲午夜在线观看| 亚洲裸体俱乐部裸体舞表演av| 午夜精品国产| 亚洲小说欧美另类婷婷| 久久色在线播放| 欧美一级淫片播放口| 欧美激情视频一区二区三区在线播放 | 欧美va天堂在线| 国产精品午夜国产小视频| 亚洲电影免费观看高清完整版在线| 国产女优一区| 日韩视频专区| 亚洲免费观看高清完整版在线观看熊 | 亚洲欧美日韩精品久久亚洲区| 亚洲国产99| 久久av在线看| 久久成人av少妇免费| 欧美性一区二区| 亚洲精品中文字幕在线观看| 亚洲黄色性网站| 久久日韩精品| 毛片基地黄久久久久久天堂| 国产欧美日韩不卡| 午夜精品久久99蜜桃的功能介绍| 亚洲午夜小视频| 欧美色图天堂网| 亚洲精品日产精品乱码不卡| 亚洲日本黄色| 牛牛影视久久网| 亚洲电影免费观看高清完整版在线观看 | 亚洲人体偷拍| 美脚丝袜一区二区三区在线观看| 久久乐国产精品| 国精品一区二区| 欧美资源在线| 榴莲视频成人在线观看| 国内精品久久久久影院薰衣草| 亚洲欧美视频在线观看| 久久精品日韩欧美| 极品少妇一区二区三区| 久久在线91| 最新中文字幕亚洲| 一区二区日韩精品| 国产精品青草综合久久久久99| 亚洲欧美不卡| 久久综合九色综合网站| 亚洲高清不卡av| 欧美激情女人20p| 亚洲特黄一级片| 久久婷婷av| 99成人精品| 国产精品va在线| 欧美在线精品一区| 亚洲国产精品一区在线观看不卡| 一个色综合导航| 国产日韩欧美综合| 美国十次了思思久久精品导航| 亚洲精品国精品久久99热| 欧美亚洲免费电影| 亚洲第一网站免费视频| 欧美日韩国产专区| 欧美一区二区三区久久精品茉莉花| 麻豆成人在线观看| 亚洲视频在线观看视频| 韩日欧美一区| 欧美三日本三级少妇三99| 久久国产精品亚洲77777| 亚洲福利视频二区| 在线看成人片| 国产精品乱码久久久久久| 久久久免费精品视频| 亚洲免费成人av| 久久中文在线| 亚洲欧美成人| 欧美日韩成人激情| 久久国产精品99国产精| 亚洲精品免费一二三区| 久久久人成影片一区二区三区 | 欧美成人高清视频| 欧美一级视频| 99视频精品在线| 亚洲电影免费观看高清| 久久免费99精品久久久久久| 一区二区三区国产| 亚洲国产三级| 精品99视频| 国产伪娘ts一区| 国产精品久久久久久久久久久久 | 亚洲国产精品一区二区www| 欧美一级在线亚洲天堂| 一区二区av在线| 亚洲精选一区| 亚洲国产成人av在线| 国内综合精品午夜久久资源| 国产伦精品一区二区三区视频孕妇| 欧美日韩免费高清|