顯示具有 boost 標籤的文章。 顯示所有文章
顯示具有 boost 標籤的文章。 顯示所有文章

BOOST 1.35.0 is out!

boost 更新了!增加了十一個新的 library。

New Libraries
* Asio:
Portable networking, including sockets, timers, hostname resolution and socket iostreams, from Chris Kohlhoff.

* Bimap:
Boost.Bimap is a bidirectional maps library for C++. With Boost.Bimap you can create associative containers in which both types can be used as key, from Matias Capeletto.

* Circular Buffer:
STL compliant container also known as ring or cyclic buffer, from Jan Gaspar.

* Function Types:
Boost.FunctionTypes provides functionality to classify, decompose and synthesize function, function pointer, function reference and pointer to member types. From Tobias Schwinger.

* Fusion:
Library for working with tuples, including various containers, algorithms, etc. From Joel de Guzman, Dan Marsden and Tobias Schwinger.

* GIL:
Generic Image Library, from Lubomir Bourdev and Hailin Jin.

* Interprocess:
Shared memory, memory mapped files, process-shared mutexes, condition variables, containers and allocators, from Ion Gaztañaga.

* Intrusive:
Intrusive containers and algorithms, from Ion Gaztañaga.

* Math/Special Functions:
A wide selection of mathematical special functions from John Maddock, Paul Bristow, Hubert Holin and Xiaogang Zhang.

* Math/Statistical Distributions:
A wide selection of univariate statistical distributions and functions that operate on them from John Maddock and Paul Bristow

* MPI:
Message Passing Interface library, for use in distributed-memory parallel application programming, from Douglas Gregor and Matthias Troyer.

* System:
Operating system support, including the diagnostics support that will be part of the C++0x standard library, from Beman Dawes.

加了不少實用的東西,看來至少可以先玩玩 ASIO 還有 MPI 看看...

Boost Libraries: Foreach

BOOST_FOREACH 是甚麼?

在 C++ 中,寫一個 iterate 一整個 sequence 的迴圈是讓人厭煩的,我們可以用 iterators,但是需要寫很多照本宣科的程式碼。或是我們可以用 std::for_each() 演算法,但是其實它也沒有省下多少功夫。相對之下,像是 Perl 之類的語言提供了內建的 "foreach" 來自動建構這樣的程序。BOOST_FOREACH 就是這類程序的 C++ 版本。它會直接幫助我們 iterates 整個 seqeuce,讓我們不用跟 iterators 奮鬥。

BOOST_FOREACH 是為了簡單易用以及有效率而設計的,他不會做動態 allocation,沒有 virtual function calls 也不用任何的 function pointers。這讓它可以產生 near-optimal 的程式碼,BOOST_FOREACH 的效率通常只跟手寫的 loop 差了幾個百分比而已。儘管 BOOST_FOREACH 是一個 macro,他的表現相當的出色。它剛好 evaluate 他的 argument 一次,讓我們不會看到有預期之外的效果。

Hello, world!

下面是一個簡單的程式,它使用了 BOOST_FOREACH 來 iterate 一個 std::string 的內容。
#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );
    
    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}
程式會 output
Hello world!
支援的類型

BOOST_FOREACH 會 iterates seqeuces,不過甚麼才會真正的組成一個 sequence?BOOST_FOREACH 是建構在 Boost.Range 之上,所以它自然會支援那些 Boost.Range 可以辨認的類型。舉例來說,我們可以用:
    * STL containers
    * arrays
    * Null-terminated strings (char and wchar_t)
    * std::pair of iterators
範例

下面是幾個使用 BOOST_FOREACH 的範例: 在 STL container 做 iterate:
std::list list_int( /*...*/ );
BOOST_FOREACH( int i, list_int )
{
    // do something with i
}
在 array 上面做 iterate with covariance (就是說 iteration variable 跟 element 的型別不完全一致)
short array_short[] = {1,2,3};
BOOST_FOREACH( int i, array_short )
{
    // The short was implicitly converted to an int
}
在 loop 中使用 return, continue 以及 break
std::deque deque_int( /*...*/ );
int i = 0;
BOOST_FOREACH( i, deque_int )
{
    if( i == 0 ) return;
    if( i == 1 ) continue;
    if( i == 2 ) break;
}
透過 reference iterate 整個 sequence,並且做變更
short array_short[] = { 1, 2, 3 };
BOOST_FOREACH( short & i, array_short )
{
    ++i;
}
// array_short contains {2,3,4} here
利用巢狀 BOOST_FOREACH iterate 一個二維 vector
std::vector<std::vector<int> > matrix_int;
BOOST_FOREACH( std::vector<int> & row, matrix_int )
    BOOST_FOREACH( int & i, row )
        ++i;

Boost Libraries: Format

在傳統的 C 語言當中,處理 output 的問題我們會用 printf 這個 function。藉由 printf 的格式化輸出,可以方便的做些簡單的排版輸出。等到進入了 C++ 時代,cout 取代了 printf,但是卻失去了原本好用的格式化輸出,使得有時候處理 output 會變成一件繁瑣的事情。boost::format 就是為了這個而生。

Synopsis
一個 format 物件是經由 format-string 和其後的參數建構而來,後面傳進來的參數是以 operator % 來做連接的。每一個參數都會被轉型成為 string 的型式,接著在依照 format-string 的樣子轉換成一個 string。下面是一個例子:
cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
     // prints "writing toto,  x=40.230 : 50-th try"

How it works
  1. 當你呼叫 format(s) 時,它將會建構一個 format 物件,並且 parse 其中的 format string 給下一個步驟使用。
  2. 接著,可能是馬上,就像
    cout << format("%2% %1%") % 36 % 77 ;
    
    或是稍後,就像
    format fmter("%2% %1%");
    fmter % 36; fmter % 77;
    
    你把變數「餵」到 format 當中,這些變數會變成所謂的 internal stream,它們的 state 是由之前的 format-string 所決定的,接著 format string 將會儲存這些結果給下一步使用。
  3. 當所有的參數都被餵進去之後,你可以把 format dump 到一個 stream 當中,或是透過 member function str() 轉成一個 string。如例子:
    // fmter was previously created and fed arguments, it can print the result :
    cout << fmter ;  
    
    // You can take the string result :
    string s  = fmter.str();
    
    // possibly several times :
    s = fmter.str( );
    
    // You can also do all steps at once :
    cout << boost::format("%2% %1%") % 36 % 77; 
    
    // using the str free function :
    string s2 = str( format("%2% %1%") % 36 % 77 );
    
    
  4. 另外,你還可以重新使用用過的 format object,來降低處理的複雜度。

Examples
  • 簡單的 output,有 re-ordering:
    cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.
    
    將會輸出 "11 22 333 22 11 \n"
  • 更精確的格式輸出:
    cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;     // Posix-Printf style
    
    會輸出:"(x,y) = ( -23, +35) \n"
  • 傳統的 printf 語法,沒有 re-ordering:
    cout << format("writing %s,  x=%s : %d-th step \n") % "toto" % 40.23 % 50; 
    
    輸出:"writing toto, x=40.23 : 50-th step \n"
  • 幾種表達同樣東西的方法:
    cout << format("(x,y) = (%+5d,%+5d) \n") % -23 % 35;
    cout << format("(x,y) = (%|+5|,%|+5|) \n") % -23 % 35;
    
    cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;
    cout << format("(x,y) = (%|1$+5|,%|2$+5|) \n") % -23 % 35;
    
    這些都代表著:"(x,y) = ( -23, +35) \n"
  • 使用 manipulators 去修改 format-string
    format fmter("_%1$+5d_ %1$d \n");
    
    format fmter2("_%1%_ %1% \n");
    fmter2.modify_item(1, group(showpos, setw(5)) ); 
    
    cout << fmter % 101 ;
    cout << fmter2 % 101 ;
    
    都是代表著 "_ +101_ 101 \n"
  • 使用有參數的 manipulators:
    cout << format("_%1%_ %1% \n") % group(showpos, setw(5), 101);
    
    manipulators 會在每個有 %1% 的地方作用,因此會輸出 "_ +101_ +101 \n"
  • 新的 format features:"absolute tabulations",在迴圈當中相當有用,可以確定一個欄位在每一行都是輸出在同一個位置。
    for(unsigned int i=0; i < names.size(); ++i)
        cout << format("%1%, %2%, %|40t|%3%\n") % names[i] % surname[i] % tel[i];
    
    可能的輸出會如下:
    Marc-François Michel, Durand,           +33 (0) 123 456 789
    Jean, de Lattre de Tassigny,            +33 (0) 987 654 321
    
其他的部分可以在 boost format 的 document 當中看到,不過大概看過這些就可以應用了。

Boost Libraries: Timer

在寫程式的時候,我們常常會希望知道程式總共跑了多久,或是某個 function 需要執行多久,來瞭解我們的 performance。通常會使用的方法是利用 time.h 裡面的 clock() 來達到我們想要的目的,程式大概會長這樣:
#include <ctime>
#include <iostream>

using namespace std ;

int main( void ) {
   clock_t t = clock() ;
   // do something....
   cout << "The program runs " << (clock()-t)/CLK_TCK << 
   " seconds" << endl ;
   return 0 ;
}

這樣當然是沒啥不好的,不過人總是懶惰,有時候會覺得要寫那麼多行 code 是很麻煩的事情。所以就有了 boost::timer 的誕生。
Boost timer 的使用相當簡單,基本上只有三個 class。接下來就一一介紹。

Class Timer
timer 這個 class 會測量經過的時間,通常使用在程式當中一些比較繁瑣的 timing 測量方面。實做其實就是利用上面講過的 clock() function。要注意的是,timer 最多可以測量的時間大概是 596.5 小時(或是更少)。以下是一個簡單的例子:
#include <boost/timer.hpp>
#include <iostream>

using namespace std ;
using namespace boost ;

int main( void ) {
  timer t1 ;
  // do something..
  cout << t1.elapsed() << endl ;

  return 0 ;
}

如此便可以輸出 t1 這個 timer 經過的時間。

Class progress_timer
progress_timer 跟 timer 很相似,差別是在它會自動在 destruction 的時候輸出 progress_timer 所經過的時間。例子如下:
#include <boost/progress.hpp>
int main()
{
   progress_timer t;  // start timing
   // do something ...
   return 0;
}

如此程式會於結束的時候輸出如 0.06 s 之類的訊息:

Class progress_display
progress_display 這個 class 則就是傳統我們會看到的 progress bar 功能。這個只是要給人看,讓人知道這隻程式正在跑。舉例來說,如果我們想要來在 map 當中插入 element,在插入的途中想利用 progress_display 來知道進度,可以用以下的 code:
#include <boost/progress.hpp>
#include <map>
#include <iostream>

using namespace std ;
using namespace boost ;

int main( void ) {
  map big_map ;
  progress_display show_progress( 1000000 ) ;

  for ( int i = 0 ; i < 1000000 ; i++ ) {
    big_map.insert( make_pair(i,i) ) ;
    ++show_progress ;
  }

  return 0 ;
}
在大約有 70% 的 element 被插入時,progress_display 會顯示
0%   10   20   30   40   50   60   70   80   90   100%
|----|----|----|----|----|----|----|----|----|----|
************************************
 

Popular Posts