版權所有 © 2003-2006 Thorsten Ottosen
使用、修改和散佈受 Boost 軟體授權條款 1.0 版約束(請參閱 https://boost.dev.org.tw/LICENSE_1_0.txt)。
operator,()
的實際用途似乎不多.
Bjarne Stroustrup,《C++ 的設計與演化》
這個函式庫的目的是透過重載 operator,()
和 operator()()
,讓使用資料填充容器變得容易。這兩個運算子使得建構數值列表成為可能,然後這些數值會被複製到容器中。
vector<int> v; v += 1,2,3,4,5,6,7,8,9;
map<string,int> m; insert( m )( "Bar", 1 )( "Foo", 2 );
這些列表在學習、測試和原型設計的情況下特別有用,但也可以在其他情況下派上用場。該函式庫附帶了標準函式庫容器的預定義運算子,但大多數功能將適用於任何符合標準的容器。該函式庫也使得擴充使用者定義的類型成為可能,因此例如可以為數值列表呼叫成員函式,而不是其一般引數。
在兩分鐘內,您應該就能使用這個函式庫。以下章節說明了主要元件
operator+=()
operator()()
list_of()
map_list_of()
tuple_list_of()
repeat()
、repeat_fun()
和 range()
ref_list_of()
和 cref_list_of()
ptr_push_back()、ptr_push_front()
、ptr_insert()
和 ptr_map_insert()
ptr_list_of()
operator+=()
要使用 operator+=()
填充向量(或任何標準容器)的值,您可以寫
這裡我們只將常數填入容器中,但只要每個運算式的結果可以轉換為容器的#include <boost/assign/std/vector.hpp> // for 'operator+=()' #include <boost/assert.hpp> using namespace std; using namespace boost::assign; // bring 'operator+=()' into scope { vector<int> values; values += 1,2,3,4,5,6,7,8,9; // insert values at the end of the container BOOST_ASSERT( values.size() == 9 ); BOOST_ASSERT( values[0] == 1 ); BOOST_ASSERT( values[8] == 9 ); }
value_type
,該列表就可以包含任意的運算式。
operator()()
我們不直接呼叫 operator()()
,而是呼叫一個返回代理物件的函式,該代理物件定義了 operator()()
。返回代理物件的函式始終以用於將列表中的值複製到容器中的成員函式命名。因此,要用成對的值填充映射,您可以寫
請注意,當我們需要使用多個引數(預設支援最多五個引數,但限制可以自訂)建構物件時,#include <boost/assign/list_inserter.hpp> // 用於 'insert()' #include <boost/assert.hpp> #include <string> using namespace std; using namespace boost::assign; // 將 'insert()' 帶入範圍 { map<string,int> months; insert( months ) ( "january", 31 )( "february", 28 ) ( "march", 31 )( "april", 30 ) ( "may", 31 )( "june", 30 ) ( "july", 31 )( "august", 31 ) ( "september", 30 )( "october", 31 ) ( "november", 30 )( "december", 31 ); BOOST_ASSERT( months.size() == 12 ); BOOST_ASSERT( months["january"] == 31 ); }
operator()()
會方便得多。序列也是如此除了#include <boost/assign/list_inserter.hpp> // for 'push_front()' #include <boost/assert.hpp> #include <string> #include <utility> using namespace std; using namespace boost::assign; // bring 'push_front()' into scope { typedef pair< string,string > str_pair; deque<str_pair> deq; push_front( deq )( "foo", "bar")( "boo", "far" ); BOOST_ASSERT( deq.size() == 2 ); BOOST_ASSERT( deq.front().first == "boo" ); BOOST_ASSERT( deq.back().second == "bar" ); }
push_front()
之外,如果容器有對應的成員函式,我們也可以使用 push_back()
。空括號可用於插入預設建構的物件,例如,push_front( deq )()()
將插入兩個預設建構的 str_pair
物件。
如果 operator()()
與 push_front()
等一起使用太麻煩,我們也可以說
deque<int> di; push_front( di ) = 1,2,3,4,5,6,7,8,9; BOOST_ASSERT( di.size() == 9 ); BOOST_ASSERT( di[0] == 9 );
為了清楚起見,上面的程式碼不限於標準容器,但會與所有具有正確成員函式的符合標準的容器一起使用。只有 operator+=()
被限制在標準容器中。
list_of()
list_of()
發揮作用的地方。使用 list_of()
,我們可以建立自動轉換為任何容器的匿名列表如果我們需要初始化容器配接器,我們需要透過呼叫#include <boost/assign/list_of.hpp> // for 'list_of()' #include <boost/assert.hpp> #include <list> #include <stack> #include <string> using namespace std; using namespace boost::assign; // bring 'list_of()' into scope { const list<int> primes = list_of(2)(3)(5)(7)(11); BOOST_ASSERT( primes.size() == 5 ); BOOST_ASSERT( primes.back() == 11 ); BOOST_ASSERT( primes.front() == 2 ); const stack<string> names = list_of( "Mr. Foo" )( "Mr. Bar")( "Mrs. FooBar" ).to_adapter(); const stack<string> names2 = (list_of( "Mr. Foo" ), "Mr. Bar", "Mrs. FooBar" ).to_adapter(); BOOST_ASSERT( names.size() == 3 ); BOOST_ASSERT( names.top() == "Mrs. FooBar" ); }
to_adapter()
來幫助編譯器。如第二個範例所示,如果我們在整個右側加上括號,則可以使用帶有 list_of()
的逗號分隔列表。值得注意的是,list_of()
的第一個引數決定了匿名列表的類型。就堆疊而言,匿名列表由 const char*
物件組成,然後將其轉換為 string
物件的堆疊。只要儲存類型之間的轉換是可能的,轉換總是可能的。
請注意,list_of()
甚至可以轉換為 boost::
array<T,sz>
,並查看 支援的函式庫清單。
請注意,list_of()
(及其變體)返回的類型具有重載的比較運算子。這允許您編寫測試程式碼,例如 BOOST_CHECK_EQUAL( my_container, list_of(2)(3)(4)(5) );.
map_list_of()
也可以使用函式#include <boost/assign/list_of.hpp> // for 'map_list_of()' #include <boost/assert.hpp> #include <map> using namespace std; using namespace boost::assign; // bring 'map_list_of()' into scope { map<int,int> next = map_list_of(1,2)(2,3)(3,4)(4,5)(5,6); BOOST_ASSERT( next.size() == 5 ); BOOST_ASSERT( next[ 1 ] == 2 ); BOOST_ASSERT( next[ 5 ] == 6 ); // or we can use 'list_of()' by specifying what type // the list consists of next = list_of< pair<int,int> >(6,7)(7,8)(8,9); BOOST_ASSERT( next.size() == 3 ); BOOST_ASSERT( next[ 6 ] == 7 ); BOOST_ASSERT( next[ 8 ] == 9 ); }
pair_list_of()
。tuple_list_of()
tuple_list_of()
可能很方便#include <boost/assign/list_of.hpp> #include <vector> using namespace std; using namespace boost::assign; { typedef boost::tuple<int,std::string,int> tuple; vector<tuple> v = tuple_list_of( 1, "foo", 2 )( 3, "bar", 4 ); BOOST_CHECK( v.size() == 2 ); BOOST_CHECK( boost::get<0>( v[1] ) == 3 ); }
repeat()
、repeat_fun()
和 range()
有時,多次重複相同的值太令人煩躁。這就是 repeat()
可以派上用場的地方
如我們所見,#include <boost/assign/list_of.hpp> #include <boost/assign/std/vector.hpp> #include <boost/assert.hpp> using namespace std; using namespace boost::assign; { vector<int> v; v += 1,2,3,repeat(10,4),5,6,7,8,9; // v = [1,2,3,4,4,4,4,4,4,4,4,4,4,5,6,7,8,9] BOOST_ASSERT( v.size() == 3 + 10 + 5 ); v = list_of(1).repeat(5,2)(3); // v = [1,2,2,2,2,2,3] BOOST_ASSERT( v.size() == 1 + 5 + 1 ); push_back( v )(1).repeat(1,2)(3); // v = old v + [1,2,3] BOOST_ASSERT( v.size() == 10 ); }
repeat()
的第一個引數是要重複第二個引數的次數。
可以使用 repeat_fun()
建構更通用的列表
對#include <boost/assign/std/vector.hpp> #include <boost/assert.hpp> #include <cstdlib> // for 'rand()' using namespace std; using namespace boost::assign; template< class T > struct next { T seed; next( T seed ) : seed(seed) { } T operator()() { return seed++; } }; { vector<int> v; v += 1,2,repeat_fun(4,&rand),4; // v = [1,2,?,?,?,?,4] BOOST_ASSERT( v.size() == 7 ); push_back( v ).repeat_fun(4,next<int>(0))(4).repeat_fun(4,next<int>(5)); // v = old v + [0,1,2,3,4,5,6,7,8] BOOST_ASSERT( v.size() == 16 ); }
repeat_fun()
的第二個引數的唯一要求是它是零元函式。
如果您只需要將迭代器範圍插入列表中的某個位置,則成員函式 range()
提供了您想要的內容。它基於 Boost.Range,因此您可以傳遞該函式庫支援的所有範圍。例如
如您所見,如果更合適,也可以傳遞兩個迭代器。最後一個範例還介紹了參考列表。更多關於以下內容。#include <boost/assign/list_inserter.hpp> // for 'push_back()' #include <boost/assign/list_of.hpp> // for 'list_of()' and 'ref_list_of()' #include <boost/assert.hpp> using namespace std; using namespace boost::assign; { vector<int> v, v2; v = list_of(1)(2)(3); v2 = list_of(0).range(v).range(v.begin(),v.end())(4); // v2 = [0,1,2,3,1,2,3,4] BOOST_ASSERT( v2.size() == 8u ); push_back( v ).range(v2)(5); // v = [1,2,3,0,1,2,3,1,2,3,4,5] BOOST_ASSERT( v.size() == 12u ); // // create a list of references, some coming from a container, others from the stack // int x = 0; int y = 1; BOOST_ASSERT( ref_list_of<10>(x).range(v2)(y).size() == 10u ); }
ref_list_of()
和 cref_list_of()
您只能將左值與#include <boost/assign/list_of.hpp> #include <algorithm> // // Define Range algorithm // template< class Range > typename Range::const_iterator max_element( const Range& r ) { return std::max_element( r.begin(), r.end() ); } using namespace boost::assign; { int a=1,b=5,c=3,d=4,e=2,f=9,g=0,h=7; int& max = *max_element( ref_list_of<8>(a)(b)(c)(d)(e)(f)(g)(h) ); BOOST_CHECK_EQUAL( max, f ); max = 8; BOOST_CHECK_EQUAL( f, 8 ); const int& const_max = *max_element(cref_list_of<8>(a)(b)(c)(d)(e)(f)(g)(h) ); BOOST_CHECK_EQUAL( max, const_max ); }
ref_list_of()
一起使用,而 cref_list_of()
也接受右值。請勿擔心沒有準確指定正確的大小;使用的額外空間最少,且沒有與之相關的執行階段開銷。如果速度至關重要,您也可以使用這些函式代替 list_of()
。作為最後一個範例,讓我們假設我們需要追蹤足球比賽的結果。如果球隊獲勝,它將獲得一分,否則為零分。如果每個組別都打了三場比賽,程式碼可能如下所示
在第一個範例中,請注意#include <boost/assign/list_of.hpp> #include <boost/assign/list_inserter.hpp> #include <boost/assert.hpp> #include <string> #include <vector> using namespace std; using namespace boost::assign; { typedef vector<int> score_type; typedef map<string,score_type> team_score_map; typedef pair<string,score_type> score_pair; team_score_map group1, group2; // // method 1: using 'insert()' // insert( group1 )( "Denmark", list_of(1)(1) ) ( "Germany", list_of(0)(0) ) ( "England", list_of(0)(1) ); BOOST_ASSERT( group1.size() == 3 ); BOOST_ASSERT( group1[ "Denmark" ][1] == 1 ); BOOST_ASSERT( group1[ "Germany" ][0] == 0 ); // // method 2: using 'list_of()' // group2 = list_of< score_pair > ( "Norway", list_of(1)(0) ) ( "USA", list_of(0)(0) ) ( "Andorra", list_of(1)(1) ); BOOST_ASSERT( group2.size() == 3 ); BOOST_ASSERT( group2[ "Norway" ][0] == 1 ); BOOST_ASSERT( group2[ "USA" ][0] == 0 ); }
list_of()
的結果如何自動轉換為 vector<int>
,因為 insert()
知道它需要 vector<int>
。在第二個範例中,我們可以看到 list_of()
有點不太聰明,因為這裡需要明確告知它預期什麼引數。(未來,可能可以在 list_of()
中引入更智慧的轉換層。)
ptr_push_back()、ptr_push_front()
、ptr_insert()
和 ptr_map_insert()
new
請注意,您可以為這些函式提供範本引數。此引數決定了要使用#include <boost/assign/ptr_list_inserter.hpp> // for 'ptr_push_back()', 'ptr_insert()' and 'ptr_push_front()' #include <boost/assign/ptr_map_inserter.hpp> // for 'ptr_map_insert()' #include <boost/ptr_container/ptr_deque.hpp> #include <boost/ptr_container/ptr_set.hpp> #include <boost/ptr_container/ptr_map.hpp> // // Example class // struct Foo { int i; Foo() : i(0) { } Foo( int i ) : i(i) { } Foo( int i, int ) : i(i) { } Foo( const char*, int i, int ) : i(i) { } virtual ~Foo() {} }; struct Bar : Foo { Bar() { } Bar( int i ) : Foo( 42 ) { } }; // // Required by ptr_set<Foo> // inline bool operator<( Foo l, Foo r ) { return l.i < r.i; } using namespace boost; using namespace boost::assign; int main() { ptr_deque<Foo> deq; ptr_push_back( deq )()(); BOOST_ASSERT( deq.size() == 2u ); ptr_push_back<Bar>( deq )()(); // insert 'Bar' objects BOOST_ASSERT( deq.size() == 4u ); ptr_push_front( deq )( 3 )( 42, 42 )( "foo", 42, 42 ); BOOST_ASSERT( deq.size() == 7u ); ptr_set<Foo> a_set; ptr_insert( a_set )()( 1 )( 2, 2 )( "foo", 3, 3 ); BOOST_ASSERT( a_set.size() == 4u ); ptr_insert( a_set )()()()(); BOOST_ASSERT( a_set.size() == 4u ); // duplicates not inserted ptr_insert<Bar>( a_set )( 42 ); // insert a 'Bar' object BOOST_ASSERT( a_set.size() == 5u ); ptr_map<int,Foo> a_map; ptr_map_insert( a_map )( 1 )( 2, 2 )( 3, 3, 3 )( 4, "foo", 4, 4 ); ptr_map_insert<Bar>( a_map )( 42, 42 ); // insert a 'Bar' object }
new
分配的類型。當容器基於抽象類型時,您必須指定此引數(因為無法建立此類型的物件)。對於 ptr_map_insert()
,引數元組 (arg1,arg2,...,argN)
中的第一個引數 arg1
用於建構索引鍵;這表示第一個引數只需要可轉換為容器的 key_type
。其餘引數用於建構映射的物件。
ptr_list_of()
list_of()
來初始化容器一樣,您可以使用 ptr_list_of()
來初始化指標容器。以下是一個簡單的範例:請注意,可以添加一個尾隨的#include <boost/assign/ptr_list_of.hpp> #include <boost/ptr_container/ptr_deque.hpp> using namespace boost; using namespace boost::assign; { ptr_deque<Foo> deq; deq = ptr_list_of<Foo>( 42 )()()( 3, 3 )( "foo", 2, 1 ); BOOST_CHECK( deq.size() == 5 ); }
.to_container(deq)
來幫助許多較差的編譯器理解轉換(少數編譯器可以正確理解)。另請注意,不支援指標映射。就這樣;現在您可以使用這個函式庫了。
值得注意的是這個函式庫的實作方式。一個獨立函式(例如 push_back()
或 operator+=()
)會回傳一個代理物件,該物件負責插入或賦值。代理物件透過重載 operator,()
和 operator()()
,以及從這些運算子內部呼叫「insert」函式來完成插入或賦值。「insert」函式通常透過使用 boost:: function
儲存在代理物件中。
通常不鼓勵重載 operator,()
,因為它可能導致意想不到的結果,但是這個函式庫採用的方法是安全的,因為使用者永遠不會直接處理具有重載 operator,()
的物件。但是,您應該注意這一點。
逗號分隔列表中的運算式不再遵循內建逗號運算子的規則。這表示逗號分隔列表中運算式的求值順序是未定義的,就像指定函式引數列表一樣。
本文檔中的大多數程式碼在範例中使用 int
,但當然它適用於任意類型,只要它們是可複製建構的即可。插入的資料不必是常數資料,可以是變數或從函式回傳的資料;唯一的要求是資料的類型可以轉換為儲存在容器中的類型。
所有轉發都是透過傳遞 const
參考的物件來完成的。最初,引數是透過傳值傳遞的(在 tuple_list_of()
中仍然如此)。要記住的一件事是,可以使用 boost:: ref
來傳遞參考。
所有內容都放在命名空間 boost::assign
中。
更多詳細資訊可以在下面找到
list_of()
和 map_list_of()
repeat()
、repeat_fun()
和 range()
list_inserter
make_list_inserter()
下面給出了此函式庫中標頭的概述。請注意,每個定義 operator+=()
的標頭都包含了 <boost/assign/list_inserter.hpp>
。
標頭 | 包含 |
---|---|
<boost/assign.hpp> | 除了指標容器的支援之外的所有內容 |
<boost/assign/list_of.hpp> | list_of() 、map_list_of() 、tuple_list_of()、ref_list_of() 和 cref_list_of() |
<boost/assign/std.hpp> | 所有標準容器的 operator+=() (請參閱下文) |
<boost/assign/std/deque.hpp> | std::deque 的 operator+=() 、<deque> |
<boost/assign/std/list.hpp> | std::list 的 operator+=() 、<list> |
<boost/assign/std/map.hpp> | std::map 和 std::multimap 的 operator+=() 、<map> |
<boost/assign/std/queue.hpp> | std::queue 和 std::priority_queue 的 operator+=() 、<queue> |
<boost/assign/std/set.hpp> | std::set 和 std::multiset 的 operator+=() 、<set> |
<boost/assign/std/slist.hpp> | 如果類別可用,則為 std::slist 的 operator+=() 、<slist> |
<boost/assign/std/stack.hpp> | std::stack 的 operator+=() 、<stack> |
<boost/assign/std/vector.hpp> | std::vector 的 operator+=() 、<vector> |
<boost/assign/assignment_exception.hpp> | 類別 assignment_exception ,可能由 list_of() 回傳的代理物件拋出 |
<boost/assign/list_inserter.hpp> | 函式 make_list_inserter() 、push_back() 、push_front() 、insert() 、push() 和類別 list_inserter ,這是整個函式庫的基礎。 |
<boost/assign/ptr_list_inserter.hpp> | 函式 ptr_push_back() 、ptr_push_front() 和 ptr_insert() |
<boost/assign/ptr_map_inserter.hpp> | 函式 ptr_map_insert() |
<boost/assign/ptr_list_of.hpp> | 函式 ptr_list_of() |
在以下內容中,三個點 (...) 表示實作定義。operator+=()
回傳一個代理物件,該物件會將呼叫轉發至 push_back()
、insert()
或 push()
,具體取決於容器支援的操作。
請注意,額外的範本引數namespace boost { namespace assign { template< class V, class A, class V2 > list_inserter< ... > operator+=( std::deque<V,A>& c, V2 v ); template< class V, class A, class V2 > list_inserter< ... > operator+=( std::list<V,A>& c, V2 v ); template< class K, class V, class C, class A, class P > list_inserter< ... > operator+=( std::map<K,V,C,A>& m, const P& p ); template< class K, class V, class C, class A, class P > list_inserter< ... > operator+=( std::multimap<K,V,C,A>& m, const P& p ); template< class V, class C, class V2 > list_inserter< ... > operator+=( std::queue<V,C>& c, V2 v ); template< class V, class C, class V2 > list_inserter< ... > operator+=( std::priority_queue<V,C>& c, V2 v ); template< class K, class C, class A, class K2 > list_inserter< ... > operator+=( std::set<K,C,A>& c, K2 k ); template< class K, class C, class A, class K2 > list_inserter< ... > operator+=( std::multiset<K,C,A>& c, K2 k ); #ifdef BOOST_HAS_SLIST template< class V, class A, class V2 > list_inserter< ... > operator+=( std::slist<V,A>& c, V2 v ); #endif template< class V, class C, class V2 > list_inserter< ... > operator+=( std::stack<V,C>& c, V2 v ); template< class V, class A, class V2 > list_inserter< ... > operator+=( std::vector<V,A>& c, V2 v ); } // namespace 'assign' } // namespace 'boost'
V2
等是必要的,以允許可轉換為 V
的類型。list_of()
和 map_list_of()
這兩個函式用於建構匿名列表,該列表可以轉換為任何標準容器和 boost::
array<T,sz>。
這兩個函式回傳的物件保證具有以下描述的介面。
namespace boost { namespace assign { template< class T > class Implementation-defined { public: const_iterator begin() const; const_iterator end() const; template< class U > Implementation-defined& operator,( U u ); // inserts default-constructed object Implementation-defined& operator()(); template< class U > Implementation-defined& operator()( U u ); template< class U, class U2 > Implementation-defined& operator()( U u, U2 u2 ); // // and similarly up to 5 arguments // // // Convert to a 'Container'. 'Container' must have a constructor // which takes two iterators. // template< class Container > operator Container() const; // // Convert to a container adapter like 'std::stack<>'. // Convertible-to-adapter to_adapter() const; // // // Convert to eg. 'boost::array<T,std::size_t>'. If the // assigned variable is too small, // a assignment_exception is thrown. // If the assigned variable it is too big, the rest of the // values are default-constructed. // template< template <class,std::size_t> class Array, class U, std::size_t sz > operator Array<U,sz>() const; }; // // Comparison operators. 'op' can be <,>,<=,>=,==,!= // template< class Range > bool op( const Implementation-defined&, const Range& ); template< class Range > bool op( const Range&, const Implementation-defined& ); template< class T > Implementation-defined list_of(); template< class T > Implementation-defined list_of( T t ); template< class T, class U, class U2 > Implementation-defined list_of( U u, U2 u2 ); template< class T, class U, class U2, class U3 > Implementation-defined list_of( U u, U2 u2, U3 u3 ); template< class T, class U, class U2, class U3, class U4 > Implementation-defined list_of( U u, U2 u2, U3 u3, U4 u4 ); template< class T, class U, class U2, class U3, class U4, class U5 > Implementation-defined list_of( U u, U2 u2, U3 u3, U4 u4, U5 u5 ); template< class Key, class T > Implementation-defined map_list_of( Key k, T t ) { return list_of< std::pair<Key,T> >()( k, t ); } } // namespace 'assign' } // namespace 'boost'
repeat()
、repeat_fun()
和 range()
這前兩個函式既以獨立函式的形式存在,也以 list_of()
回傳的物件和 list_inserter
的成員函式的形式存在。獨立版本用於建立 operator,()
的掛鉤,因此我們可以在逗號列表中間呼叫函式。當我們需要在括號列表中間呼叫函式時,使用成員函式。在這兩種情況下,我們都有
repeat()
的引數列表為 (std::size_t,T)
,以及repeat_fun()
的引數列表為 (std::size_t,Nullary_function)
函式 range()
僅以成員函式的形式存在。提供以下兩個多載
template< class SinglePassIterator > Implementation-defined range( SinglePassIterator first, SinglePassIterator last ); template< class SinglePassRange > Implementation-defined range( const SinglePassRange& rng );
list_inserter
概要
namespace boost { namespace assign { template< Function, Argument = void > class list_inserter { Function fun; public: explicit list_inserter( Function fun ); // conversion constructor template< class Function2, class Arg > list_inserter( const list_inserter<Function2,Arg>& ); public: template< class U > list_inserter& operator,( U u ); template< class U > list_inserter& operator=( U u ); // calls 'fun()' with default-constructed object list_inserter& operator()(); template< class U > list_inserter& operator()( U u ); template< class U, class U2 > list_inserter& operator()( U u, U2 u2 ) { // // if 'Argument' is 'void' // fun( u, u2 ); // else // fun( Argument( u, u2 ) ); // return *this; } // // similarly up to 5 arguments // }; template< class C > list_inserter< ... > push_back( C& ); template< class C > list_inserter< ... > push_front( C& ); template< class C > list_inserter< ... > insert( C& ); template< class C > list_inserter< ... > push( C& ); } // namespace 'assign' } // namespace 'boost'
請注意,根據 Argument
的類型,operator,()
和 operator()()
的引數如何以不同的方式傳遞給 fun
。因此,如果我們只將一個範本引數傳遞給 list_inserter
,我們可以轉發函式的「任意」引數列表。如果我們將兩個範本引數傳遞給 list_inserter
,我們可以建構具有「任意」建構函式的類型。
而且由於回傳的是 list_inserter
的參考,我們可以以非常節省空間的方式將引數列表鏈接在一起。
make_list_inserter()
一個簡單的 list_inserter
「建構函式」函式。此函式的典型用法是以 boost::bind()
的結果來呼叫它,這通常會回傳一些難以理解且奇怪的類別範本。
namespace boost { namespace assign { template< class Function > list_inserter<Function> make_list_inserter( Function fun ) { return list_inserter<Function>( fun ); } } }
此函式庫使用 boost 預處理器函式庫來實作 operator()()
和 list_of()
的多載版本。預設情況下,您可以使用五個引數呼叫這些函式,但是您也可以在包含此函式庫的標頭之前定義巨集來自訂此數字
#define BOOST_ASSIGN_MAX_PARAMS 10 #include <boost/assign.hpp>
函式庫的例外保證與轉發到的函式的保證相同。對於標準容器,這表示為單次插入提供強保證,而為多次插入提供基本保證(前提是複製的物件提供基本保證)。
函式可能會拋出標準例外,例如 std::bad_alloc
。但是請注意,不幸的是,標準不保證標準容器中的配置失敗會透過 std::bad_alloc
或衍生自 std::exception
的例外報告。
assignment_exception
例外是由 list_of()
回傳的代理物件中的轉換運算子拋出的。
namespace boost { namespace assign { class assignment_exception : public std::exception { public: explicit assignment_exception( const char* what ); virtual const char* what() const throw(); }; } }
使函式庫與新類別協同工作非常簡單。此程式碼顯示如何將 operator+=()
與容器一起使用
其中template< class V, class A, class V2 > inline list_inserter< assign_detail::call_push_back< std::vector<V,A> >, V > operator+=( std::vector<V,A>& c, V2 v ) { return make_list_inserter( assign_detail::call_push_back< std::vector<V,A> >( c ) )( v ); }
call_push_back
定義為請注意,我們將第二個範本引數傳遞給template< class C > class call_push_back { C& c_; public: call_push_back( C& c ) : c_( c ) { } template< class T > void operator()( T r ) { c_.push_back( r ); } };
list_inserter
,因此引數列表將用於建構 V
物件。否則,我們可能會嘗試以 n 個引數呼叫 push_back()
,而不是一個引數。
另一種方法是結合使用 boost::function
和 boost::bind()
。但是,在這種情況下,必須記住取標準函式庫中函式的位址是非法的。
使用多個引數呼叫函式也非常有用。這個小範例顯示了我們如何利用此功能
完整的範例可以在 email_example.cpp 中看到// // A class representing emails // class email { public: enum address_option { check_addr_book, dont_check_addr_book }; private: typedef std::map< std::string,address_option > address_map; // // Store list of persons that must be cc'ed // mutable address_map cc_list; // // This extra function-object will take care of the // insertion for us. It stores a reference to a // map and 'operator()()' does the work. // struct add_to_map { address_map& m; add_to_map( address_map& m ) : m(m) {} void operator()( const std::string& name, address_option ao ) { m[ name ] = ao; } }; public: // // This function constructs the appropriate 'list_inserter'. // Again we could have use 'boost::function', but it is // trivial to use a function object. // // Notice that we do not specify an extra template // parameter to 'list_inserter'; this means we forward // all parameters directly to the function without // calling any constructor. // list_inserter< add_to_map > add_cc( std::string name, address_option ao ) { // // Notice how we pass the arguments 'name' and 'ao' to // the 'list_inserter'. // return make_list_inserter( add_to_map( cc_list ) )( name, ao ); } }; // // Now we can use the class like this: // email e; e.add_cc( "Mr. Foo", email::dont_check_addr_book ) ( "Mr. Bar", email::check_addr_book ) ( "Mrs. FooBar", email::check_addr_book );
其他範例可以在測試檔案中找到
boost::array
boost::multi_index_container
Boost.Pointer Container
函式庫已使用 MVC++ 7.1、GCC 3.2 (在 Cygwin 下) Comeau 4.3.3 成功編譯和測試
在不支援範本轉換運算子的平台上存在已知限制。解決方法是在 list_of()
回傳的物件上呼叫某些成員函式
{ using namespace std; using namespace boost; using namespace boost::assign; vector<int> v = list_of(1)(2)(3)(4).to_container( v ); set<int> s = list_of(1)(2)(3)(4).to_container( s ); map<int,int> m = map_list_of(1,2)(2,3).to_container( m ); stack<int> st = list_of(1)(2)(3)(4).to_adapter( st ); queue<int> q = list_of(1)(2)(3)(4).to_adapter( q ); array<int,4> a = list_of(1)(2)(3)(4).to_array( a ); }
請注意,必須向函式提供引數,以便推斷正確的回傳類型。
某些標準函式庫也已損壞。一個問題是 insert()
可能不起作用
解決方案是改用map<int,int> next; insert( next )(1,2)(2,3); // compile-time error
map_list_of()
map<int,int> next = map_list_of(1,2)(2,3);
用於賦值/初始化函式庫的想法並不是新的。此函式庫的功能與 Leor Zolman 的 STL 容器初始化函式庫非常相似,但是它不依賴字串剖析來實現其目標。
這個函式庫是非侵入式的,對其支援的類別只設定最低限度的要求。重載逗號運算子有時被認為是不好的做法[1]。然而,它在諸如 Generative Matrix Computation Library 和 Blitz 等函式庫中被成功地用來初始化矩陣(請參閱 [2] 和 [3])。初始化函式庫以安全的方式重載逗號運算子,透過讓獨立函式返回一個負責初始化的物件來達成。因此,程式設計師需要明確地採取動作才能開始使用重載的 operator,()
。
最近有一些關於增強語言以支援更好的初始化的討論(請參閱 [4])。
特別感謝以下人士:
(C) 版權所有 Thorsten Ottosen 2003-2006