#眉標=Boost #副標=「Boost技術與應用」系列文章(3) #大標= Array和Any #作者=文/侯捷 ==本文相關資訊 <box>=========== ‧ 讀者基礎:擁有C++ templates編程經驗與C++標準程式庫使用經驗。 ‧ 本文測試環境:VC6(+)。 ‧ 本系列文章將匯整至編寫中的《Boost運用與源碼剖析》一書。 ==<end>============== ==<反黑>=========== int myIntArray[100]; //定義一個array,可容納100個ints ==<end>============== ==程式1 class block <box>=========== template <class T, size_t N> struct block { typedef T value_type; typedef value_type* pointer; typedef value_type& reference; typedef ptrdiff_t difference_type; typedef size_t size_type; typedef pointer iterator; reference operator[](size_type n) { return data[n]; } iterator begin() { return data; } iterator end() { return data + N; } size_type size() const { return N; } T data[N]; }; 註:取自《Generic Programming and the STL》,p.60~p.61 ==<end>============== ==程式2 class c_array <box>=========== template<class T, int max> struct c_array { typedef T value_type; typedef T* iterator; typedef T& reference; operator T*() { return v; } reference operator[](size_t i) { return v[i]; } iterator begin() { return v; } iterator end() { return v + thesize; } size_type size() const { return thesize; } T v[max]; }; 註:取自《The C++ Programming Language》3/e, p.496 ==<end>============== ==程式3 class carray <box>=========== template<class T, std::size_t thesize> class carray { public: typedef T value_type; typedef T* iterator; typedef T& reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; reference operator[](std::size_t i) { return v[i]; } iterator begin() { return v; } iterator end() { return v + thesize; } size_type size() const { return thesize; } size_type max_size() const { return thesize; } T* as_array() { return v; } private: T v[thesize]; // fixed-size array of elements of type T }; 註:取自《The C++ Standard Library》, p.219 ==<end>============== ==程式4 boost::array關鍵源碼 <box>=========== template<class T, std::size_t N> class array { public: T elems[N]; // fixed-size array of elements of type T public: // type definitions typedef T value_type; typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; // iterator support iterator begin() { return elems; } iterator end() { return elems+N; } reference operator[](size_type i) { BOOST_ASSERT( i < N && "out of range" ); return elems[i]; } reference at(size_type i) { rangecheck(i); return elems[i]; } reference front() { return elems[0]; } reference back() { return elems[N-1]; } static size_type size() { return N; } static bool empty() { return false; } static size_type max_size() { return N; } enum { static_size = N }; // direct access to data (read-only) const T* data() const { return elems; } // use array as C array (direct read/write access to data) T* c_array() { return elems; } // check range (may be private because it is static) static void rangecheck (size_type i) { if (i >= size()) { throw std::range_error("array<>: index out of range"); } } }; (摘自 \boost\include\boost-1_33\boost\array.hpp) ==<end>============== ==程式5 BOOST_ASSERT源碼<box>=========== #undef BOOST_ASSERT #if defined(BOOST_DISABLE_ASSERTS) # define BOOST_ASSERT(expr) ((void)0) #elif defined(BOOST_ENABLE_ASSERT_HANDLER) #include <boost/current_function.hpp> namespace boost { void assertion_failed(char const * expr, char const * function, char const * file, long line); // user defined } // namespace boost #define BOOST_ASSERT(expr) ((expr)? ((void)0): ::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) #else # include <assert.h> // .h to support old libraries w/o <cassert> - effect is the same # define BOOST_ASSERT(expr) assert(expr) #endif (取自\boost\include\boost-1_33\boost\assert.hpp) ==<end>============== ==程式6 測試Boost.Array <box>=========== #include <iostream> #include <boost/array.hpp> #include <algorithm> #include <functional> using namespace std; using namespace boost; template <class T> inline void print_elements (const T& coll, const char* optcstr="") { typename T::const_iterator pos; //使用const iterator為佳 cout << optcstr; //先輸出optional string for (pos=coll.begin(); pos!=coll.end(); ++pos) { cout << *pos << ' '; //逐一輸出元素 } cout << endl; } int main() { { //以下測試來自解壓縮後所得的 \boost_1_33_0\libs\array\array1.cpp typedef boost::array<float,6> Array; Array a = { 42 }; for (unsigned i=1; i<a.size(); ++i) { a[i] = a[i-1]+1; } //使用若干常見的STL容器操作函式 cout << "size: " << a.size() << endl; //6 cout << "empty: " << (a.empty() ? "true" : "false") << endl; cout << "max_size: " << a.max_size() << endl; //6 cout << "front: " << a.front() << endl; //42 cout << "back: " << a.back() << endl; //47 cout << "elems: "; //迭代穿越所有元素 for (Array::const_iterator pos=a.begin(); pos<a.end(); ++pos) { cout << *pos << ' '; } cout << endl; //42 43 44 45 46 47 //檢驗copy ctor和copy op= Array b(a); //喚起copy ctor Array c; c = a; //喚起copy op= if (a==b && a==c) { cout << "copy ctor and copy op= are OK" << endl; } else { cout << "copy ctor and copy op= FAILED" << endl; } } //scope1 { //以下測試來自解壓縮後所得的\boost_1_33_0\libs\array\array2.cpp array<int,10> a = { 1, 2, 3, 4, 5 }; print_elements(a); //1 2 3 4 5 0 0 0 0 0 //直接改動元素 for (unsigned i=0; i<a.size(); ++i) { ++a[i]; } print_elements(a); //2 3 4 5 6 1 1 1 1 1 //運用STL algorithm改變元素次序 reverse(a.begin(),a.end()); print_elements(a); //1 1 1 1 1 6 5 4 3 2 //運用STL algorithm改變元素內容(全部加上負號) transform(a.begin(),a.end(), //source a.begin(), //destination negate<int>()); //operation print_elements(a); //-1 -1 -1 -1 -1 -6 -5 -4 -3 -2 //! cout << a.at(10) << endl; //abnormal program termination //! cout << a[10] << endl; //Assertion failed: i < N && "out of range",… } //scope2 return 0; } ==<end>============== ==程式7 <box>=========== //in Boost\include\boost-1_33\boost \current_function.hpp namespace boost { namespace detail { inline void current_function_helper() { #if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) # define BOOST_CURRENT_FUNCTION __PRETTY_FUNCTION__ #elif defined(__FUNCSIG__) # define BOOST_CURRENT_FUNCTION __FUNCSIG__ #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500)) # define BOOST_CURRENT_FUNCTION __FUNCTION__ #elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550) # define BOOST_CURRENT_FUNCTION __FUNC__ #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) # define BOOST_CURRENT_FUNCTION __func__ #else # define BOOST_CURRENT_FUNCTION "(unknown)" #endif } } // namespace detail } // namespace boost ==<end>============== ==<反黑>=========== vector<Base> v; v.push_back(Derived()); v.push_back(MostDerived()); ... ==<end>============== ==<反黑>=========== vector<void*> v; v.push_back((void*)new classA); v.push_back((void*)new classB); v.push_back((void*)new classC); //以上各元素有無強制轉型為(void*)無所謂,都可通過編譯且無警告。 ((classA*)vv[0])->func(); //喚起classA::func() ((classB*)vv[1])->func(); //喚起classB::func() ((classC*)vv[2])->func(); //喚起classC::func() ... ==<end>============== ==程式8 指定容器的元素型別為any並放入6個異型物<box>=========== using namespace std; using namespace boost; ... vector<any> va; va.push_back(A()); va.push_back(B()); va.push_back(C()); va.push_back(string("a test string")); va.push_back(10); va.push_back(make_pair(true,9.28)); for_each(va.begin(), va.end(), print_any); ==<end>============== ==程式9 <box>=========== void print_any(any& a) { if (A* pA = any_cast<A>(&a)) { pA->func(); } else if (B* pB = any_cast<B>(&a)) { pB->func(); } else if (C* pC = any_cast<C>(&a)) { pC->func(); } else { try { cout << any_cast<string>(a) << endl; } catch (bad_any_cast&) { cout << "bad any cast!" << endl; } } } ==<end>============== ==程式10 <box>=========== class any { public: template<typename T> any(const T & value) //non-explicit, one-argument建構式 : content(new holder<T>(value)) { } ... ~any() { delete content; } private: placeholder* content; }; ==<end>============== ==程式11 <box>=========== class placeholder { public: virtual ~placeholder() { } public: // queries virtual const std::type_info & type() const = 0; virtual placeholder* clone() const = 0; }; ==<end>============== ==程式12 <box>=========== template<typename T> class holder : public placeholder { public: holder(const T & value) : held(value) { } ... public: T held; }; ==<end>============== == <反黑>=========== //版本一 template<typename T> T* any_cast(any* operand) { return operand && operand->type() == typeid(T) ? &static_cast<any::holder<T>*>(operand->content)->held : 0; } ==<end>============== ==<反黑>=========== operand->type() == typeid(T) ==<end>============== ==<反黑>=========== &static_cast<any::holder<T>*>(operand->content)->held ==<end>============== ==<box>=========== holder是定義於any內的一個private嵌套類別,而any_cast被定義為any的一個friend,所以any_cast()內可使用any::holder。如果編譯器不支援template friend,Boost就把holder定義為any內的一個public嵌套類別,那麼更是任何人都可以直接使用any::holder。 ==<end>============== ==<反黑>=========== //版本二 template<typename T> const T* any_cast(const any* operand) { return any_cast<T>(const_cast<any*>(operand)); } //使用版本一 ==<end>============== ==<反黑>=========== //版本三 template<typename T> T any_cast(const any& operand) { typedef remove_reference<T>::type nonref; const nonref* result = any_cast<nonref>(&operand); //使用版本二 if(!result) boost::throw_exception(bad_any_cast()); return *result; } ==<end>============== ==<反黑>=========== //版本四 template<typename T> T any_cast(any& operand) { typedef remove_reference<T>::type nonref; nonref* result = any_cast<nonref>(&operand); //使用版本一 if(!result) boost::throw_exception(bad_any_cast()); return *result; } ==<end>============== ==更多資訊 <box>=========== 以下是與本文相關的讀物或網上資源。 ‧ 《Beyond the C++ Standard Library, An Introduction to Boost》by Bjorn Karlesson, A.W. 2005. ‧ Boost Libraries Documentation, from http://www.boost.org ==<end>============== ==作者簡介 <box>=========== 侯捷 資訊顧問、專欄主筆、大學執教。常著文章自娛,頗示己志。 侯捷網站:http://www.jjhou.com(繁體) 北京鏡站:http://jjhou.csdn.net(簡體) 永久郵箱:jjhou@jjhou.com ==<end>==============