• <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>

            Boost.Singals 教程

            Posted on 2008-07-04 13:23 RichardHe 閱讀(928) 評論(0)  編輯 收藏 引用 所屬分類: [轉]
            來自http://www.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

            国产成人精品久久综合 | 亚洲狠狠综合久久| 亚洲午夜精品久久久久久app| 人妻无码久久精品| 久久久久久久久久久久中文字幕 | 精品久久久久中文字| 久久久国产打桩机| 狠狠人妻久久久久久综合蜜桃| 久久国产精品国语对白| 久久久国产精华液| 久久久久久A亚洲欧洲AV冫| 国内精品伊人久久久久| 亚洲国产另类久久久精品| 中文成人久久久久影院免费观看| 国色天香久久久久久久小说| 超级97碰碰碰碰久久久久最新| 久久久久这里只有精品| 久久久久女教师免费一区| 久久国产色av免费看| 久久er国产精品免费观看8| 国产成人精品免费久久久久| 久久久久99精品成人片直播| 色婷婷久久综合中文久久一本| 久久国产精品99精品国产987| 久久无码专区国产精品发布| 久久99精品九九九久久婷婷| 国产精品久久午夜夜伦鲁鲁| 欧美精品久久久久久久自慰| 国内精品久久久久久99蜜桃| 亚洲午夜久久久| 久久久WWW成人| 开心久久婷婷综合中文字幕| 品成人欧美大片久久国产欧美...| 激情伊人五月天久久综合| 久久99精品久久久大学生| 亚洲人AV永久一区二区三区久久| 国产激情久久久久影院老熟女免费 | 久久久久国产成人精品亚洲午夜| 国产亚洲美女精品久久久久狼| 久久久久人妻一区二区三区| 久久久久波多野结衣高潮|