• <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>
            posts - 200, comments - 8, trackbacks - 0, articles - 0
                  什么是traits,為什么人們把它認(rèn)為是C++ Generic Programming的重要技術(shù)?

                  簡(jiǎn)潔地說(shuō),traits如此重要,是因?yàn)榇隧?xiàng)技術(shù)允許系統(tǒng)在編譯時(shí)根據(jù)類型作一些決斷,就好像在運(yùn)行時(shí)根據(jù)值來(lái)做出決斷一樣。更進(jìn)一步,此技術(shù)遵循“另增一個(gè)間接層”的諺語(yǔ),解決了不少軟件工程問(wèn)題,traits使您能根據(jù)其產(chǎn)生的背景(context) 來(lái)做出抉擇。這樣最終的代碼就變得清晰易讀,容易維護(hù)。如果你正確運(yùn)用了traits技術(shù),你就能在不付出任何性能和安全代價(jià)的同時(shí)得到這些好處,或者能夠契合其他解決方案上的需求。
                  先舉個(gè)淺顯易懂的例子來(lái)說(shuō)明traits的用法:
            //首先假如有以下一個(gè)泛型的迭代器類,其中類型參數(shù) T 為迭代器所指向的類型:
            template <typename T>
            class myIterator
            {

            };
                   那么當(dāng)使用myIterator時(shí),怎樣才能知道它所指向元素的類型呢?一種解決方案是為這個(gè)類加入一個(gè)內(nèi)嵌類型:
            template <typename T>
            class myIterator
            {
            typedef T value_type;

            };
                  當(dāng)使用myIterator時(shí),可以通過(guò)myIterator::value_type來(lái)獲得相應(yīng)的myIterator所指向的類型。下面舉例使用:
            template <typename T>
            typename myIterator<T>::value_type func(myIterator<T> i)
            {

            }
                  這里定義了一個(gè)函數(shù)func,返回值類型為參數(shù)i所指的類型,也就是模板參數(shù)T,那么為什么不直接使用模板參數(shù)T,而要繞著圈去使用那個(gè)value_type呢?所以我們返回來(lái),當(dāng)修改func函數(shù)時(shí),它能夠適應(yīng)所有類型的迭代器,不是更好嗎?如下所示:
            template <typename I> //這里的I可以是任意類型的迭代器
            typename I::value_type func(I i)
            {

            }
                  現(xiàn)在,任意定義了value_type內(nèi)嵌類型的迭代器都可以做為func的參數(shù)了,并且func的返回值的類型將與相應(yīng)迭代器所指的元素的類型一致。至此一切問(wèn)題似乎都已解決,并且似乎并沒(méi)有使用任何特殊的技術(shù)。
                  然而當(dāng)考慮到以下情況時(shí),新的問(wèn)題便顯現(xiàn)出來(lái)了:原生指針也完全可以做為迭代器來(lái)使用,然而顯然沒(méi)有辦法為原生指針添加一個(gè)value_type的內(nèi)嵌類型,如此一來(lái)func()函數(shù)就不能適用原生指針了,這不能不說(shuō)是一大缺憾。那么有什么辦法可以解決這個(gè)問(wèn)題呢?此時(shí)不禁想到了用Traits萃取類型信息。可以不直接使用myIterator的value_type,而是通過(guò)Traits類來(lái)把這個(gè)信息提取出來(lái):(不同的類型,可以有不同的提取方式)
            template <typename T>
            class Traits
            {
            typedef typename T::value_type value_type;
            };
                  這樣以后就可以通過(guò)Traits<myIterator>::value_type來(lái)提取出myIterator中的value_type,于是func函數(shù)改寫(xiě)成:
            template <typename I> //這里的I可以是任意類型的迭代器
            typename Traits<I>::value_type Foo(I i)
            {

            }
                  然而,即使這樣,那個(gè)原生指針的問(wèn)題仍然沒(méi)有解決,因?yàn)門(mén)rait類還是沒(méi)辦法獲得原生指針的相關(guān)信息。于是不妨將Traits偏特化(partial specialization):(通過(guò)特化、重載特化等手段產(chǎn)出不同的提取方式)
            template <typename T>
            class Traits<T*> //注意 這里針對(duì)原生指針進(jìn)行了偏特化
            {
            typedef typename T value_type;
            };
                 通過(guò)上面這個(gè)Traits的偏特化版本,一個(gè)T*類型的指針?biāo)赶虻脑氐念愋蜑門(mén)。如此一來(lái),我們func函數(shù)就完全可以適用于原生指針了。比如:
            int * p;
            .
            int i = func(p);
                 Traits會(huì)自動(dòng)推導(dǎo)出p所指元素的類型為int,從而func正確返回。
            -----------------------------------------------------------------------------------------------------------------------------------------------------------
                 現(xiàn)在再看一個(gè)更加一般的例子——smart pointers。(智能指針)
                 假設(shè)你正在設(shè)計(jì)一個(gè)SmartPtr模板類,對(duì)于一個(gè)smart pointer 來(lái)說(shuō),它的最大的用處是可以自動(dòng)管理內(nèi)存問(wèn)題,同時(shí)在其他方面又像一個(gè)常規(guī)指針。但是有些C++的Smart pointer實(shí)現(xiàn)技術(shù)卻非常令人難以理解。這一殘酷的事實(shí)帶來(lái)了一個(gè)重要實(shí)踐經(jīng)驗(yàn):你最好盡一切可能一勞永逸,寫(xiě)出一個(gè)出色的、具有工業(yè)強(qiáng)度的 smart pointer來(lái)滿足你所有的需求。此外,你通常不能修改一個(gè)類來(lái)適應(yīng)你的smart pointer,所以你的SmartPtr一定要足夠靈活。
                 有不少類層次使用引用計(jì)數(shù)(reference counting)以及相應(yīng)的函數(shù)管理對(duì)象的生存期。然而,并沒(méi)有reference counting的標(biāo)準(zhǔn)實(shí)現(xiàn)方法,每一個(gè)C++庫(kù)的供應(yīng)商在實(shí)現(xiàn)的語(yǔ)法和/或語(yǔ)義上都有所不同。例如,在你的應(yīng)用程序中有這樣兩個(gè)interfaces:
            第一種智能指針--大部分的類實(shí)現(xiàn)了RefCounted接口:
            class RefCounted
            {
            public:
            virtual void IncRef() = 0;
            virtual bool DecRef() = 0;
            // if you DecRef() to zero references, the object is destroyed
            // automatically and DecRef() returns true
            virtual ~RefCounted() {}
            };
            第二種智能指針--第三方提供的Widget類使用不同的接口:
            class Widget
            {
            public:
            void AddReference();
            int RemoveReference(); 
            // returns the remaining number of references; it's the client's
            // responsibility to destroy the object

            };
                  不過(guò)你并不想維護(hù)兩個(gè)smart pointer類,你想讓兩種類共享一個(gè)SmartPtr。一個(gè)基于traits的解決方案把兩種不同的接口用語(yǔ)法和語(yǔ)義上統(tǒng)一的接口包裝起來(lái),建立針對(duì)普通類的通用模板,而針對(duì)Widget建立一個(gè)特殊化版本,如下:
            template <class T>
            class RefCountingTraits
            {
            static void Refer(T* p)
            {
            p->IncRef(); // assume RefCounted interface
            }
            static void Unrefer(T* p)
            {
            p->DecRef(); //assume RefCounted interface
            }
            };
            template<>
            class RefCountingTraits<Widget>
            {
            static void Refer(Widget* p)
            {
            p->AddReference(); //use Widget interface
            }
            static void Unrefer(Widget* p)
            {
            //use Widget interface
            If (p->RemoveReference() == 0)
            delete p;
            }
            };
                  在SmartPtr里,我們像這樣使用RefCountingTraits:
            template <class T>
            class SmartPtr
            {
            private:
            typedef RefCountingTraits<T> RCTraits;
            T* pointee_;
            public:

            ~SmartPtr()
            {
            RCTraits::Unrefer(pointee_);
            }
            };
                  當(dāng)然在上面的例子里,你可能會(huì)爭(zhēng)論說(shuō)你可以直接特殊化Widget類的SmartPtr的構(gòu)造與析構(gòu)函數(shù)。你可以使用把模板特殊化技術(shù)用在 SmartPtr本身,而不是用在traits上頭,這樣還可以消除額外的類。盡管對(duì)這個(gè)問(wèn)題來(lái)說(shuō)這種想法沒(méi)錯(cuò),但還是由一些你需要注意的缺陷:
            1. 這么干缺乏可擴(kuò)展性。如果給SmartPtr再增加一個(gè)模板參數(shù),你不能特殊化這樣一個(gè)SmartPtr<T. U>,其中模板參數(shù)T是Widget,而U可以為其他任何類型。
            2. 最終代碼不那么清晰。Trait有一個(gè)名字,而且把相關(guān)的東西很好的組織起來(lái),因此使用traits的代碼更加容易理解。相比之下,用直接特殊化SmartPtr成員函數(shù)的代碼,看上去更招黑客的喜歡。
                  用繼承機(jī)制的解決方案,就算本身完美無(wú)瑕,也至少存在上述的缺陷。解決這樣一個(gè)變體問(wèn)題,使用繼承實(shí)在是太笨重了。此外,通常用以取代繼承方案的另一種經(jīng)典機(jī)制——containment,用在這里也顯得畫(huà)蛇添足,繁瑣不堪。相反,traits方案干凈利落,簡(jiǎn)明有效,物合其用,恰到好處。
                  Traits的一個(gè)重要的應(yīng)用是“interface glue”(接口膠合劑),通用的、可適應(yīng)性極強(qiáng)的適配子。如果不同的類對(duì)于一個(gè)給定的概念有著不同的實(shí)現(xiàn),traits可以把這些實(shí)現(xiàn)再組織統(tǒng)一成一個(gè)公共的接口。對(duì)于一個(gè)給定類型提供多種TRAITS:現(xiàn)在,我們假設(shè)所有的人都很喜歡你的SmartPtr模板類,直到有一天,在你的多線程應(yīng)用程序里開(kāi)始現(xiàn)了神秘的bug。你發(fā)現(xiàn)罪魁禍?zhǔn)资荳idget,它的引用計(jì)數(shù)函數(shù)并不是線程安全的。現(xiàn)在你不得不親自實(shí)現(xiàn)Widget:: AddReference和Widget::RemoveReference,最合理的位置應(yīng)該是在RefCountingTraits中,打上個(gè)補(bǔ)丁吧:
            // Example 7: Patching Widget's traits for thread safety
            template <>
            class RefCountingTraits<Widget>
            {
            static void Refer(Widget* p)
            {
            Sentry s(lock_); // serialize access
            p->AddReference();
            }
            static void Unrefer(Widget* p)
            {
            Sentry s(lock_); // serialize access
            if (p->RemoveReference() == 0)
            delete p;
            }
            private:
            static Lock lock_;
            };
                   不幸的是,雖然你重新編譯、測(cè)試之后正確運(yùn)行,但是程序慢得像蝸牛。仔細(xì)分析之后發(fā)現(xiàn),你剛才的所作所為往程序里塞了一個(gè)糟糕的瓶頸。實(shí)際上只有少數(shù)幾個(gè)Widget是需要能夠被好幾個(gè)線程訪問(wèn)的,余下的絕大多數(shù)Widget都是只被一個(gè)線程訪問(wèn)的。你要做的是告訴編譯器按你的需求分別使用多線程traits和單線程traits這兩個(gè)不同版本。你的代碼主要使用單線程traits。
                   如何告訴編譯器使用哪個(gè)traits?一種方法是把traits作為另一個(gè)模板參數(shù)傳給SmartPtr。缺省情況下傳遞老式的traits模板,而用特定的類型實(shí)例化特定的模板。
            template <class T, class RCTraits = RefCountingTraits<T> >
            class SmartPtr
            {

            };
                  你對(duì)單線程版的RefCountingTraits<Widget>不做改動(dòng),而把多線程版放在一個(gè)單獨(dú)的類中:
            class MtRefCountingTraits
            {
            static void Refer(Widget* p)
            {
            Sentry s(lock_); // serialize access
            p->AddReference();
            }
            static void Unrefer(Widget* p)
            {
            Sentry s(lock_); // serialize access
            if (p->RemoveReference() == 0)
            delete p;
            }
            private:
            static Lock lock_;
            };
                   現(xiàn)在你可將SmartPtr<Widget>用于單線程目的,將SmartPtr<Widget,MtRefCountingTraits>用于多線程目的。
                   最后,以SGI STL中的__type_traits結(jié)束本篇討論,在SGI 實(shí)現(xiàn)版的STL中,為了獲取高效率,提供了__type_traits,用來(lái)提取類的信息,比如類是否擁有trival的構(gòu)造、析構(gòu)、拷貝、賦值操作,然后跟據(jù)具體的信息,就可提供最有效率的操作。以下摘錄cygwin的gcc3.3源碼,有改動(dòng),在<type_traits.h>中。
            struct __true_type {};
            struct __false_type {};
            template <class _Tp>
            struct __type_traits
            {
            typedef __true_type    this_dummy_member_must_be_first;
            typedef __false_type    has_trivial_default_constructor;
            typedef __false_type    has_trivial_copy_constructor;
            typedef __false_type    has_trivial_assignment_operator;
            typedef __false_type    has_trivial_destructor;
            typedef __false_type    is_POD_type;
            };
                    對(duì)于普通類來(lái)講,為了安全起見(jiàn),都認(rèn)為它們擁有non-trival的構(gòu)造、析構(gòu)、拷貝、賦值函數(shù),POD是指plain old data。接下來(lái)對(duì)C++的原生類型(bool,int, double之類)定義了顯式的特化實(shí)現(xiàn),以double為例:
            template<> 
            struct __type_traits<long double> {
            typedef __true_type    has_trivial_default_constructor;
            typedef __true_type    has_trivial_copy_constructor;
            typedef __true_type    has_trivial_assignment_operator;
            typedef __true_type    has_trivial_destructor;
            typedef __true_type    is_POD_type;
            };
            還有,對(duì)所有的原生指針來(lái)講,它們的構(gòu)造、析構(gòu)等操作也是trival的,因此有:
            template <class _Tp>
            struct __type_traits<_Tp*> {
            typedef __true_type    has_trivial_default_constructor;
            typedef __true_type    has_trivial_copy_constructor;
            typedef __true_type    has_trivial_assignment_operator;
            typedef __true_type    has_trivial_destructor;
            typedef __true_type    is_POD_type;
            };
                  簡(jiǎn)化<stl_algobase.h>中copy的部分代碼來(lái)說(shuō)明對(duì)__type_traits的應(yīng)用。
            template<typename _Tp>
            inline _Tp* __copy_trivial(const _Tp* __first, const _Tp* __last, _Tp* __result)
            {
            memmove(__result, __first, sizeof(_Tp) * (__last - __first));
            return __result + (__last - __first);
            }
            template<typename _Tp>
            inline _Tp* __copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __true_type)
            return __copy_trivial(__first, __last, __result); } 
            template<typename _Tp>
            inline _Tp* __copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __false_type)
            { 另外處理;}
            template<typename _InputIter, typename _OutputIter> inline 
            _OutputIter copy (_InputIter __first, _InputIter __last, _OutputIter __result)
            {
            typedef typename iterator_traits<_InputIter>::value_type _ValueType;
            typedef typename __type_traits<_ValueType>::has_trivial_assignment_operator _Trivial;
            return __copy_aux(__first, __last, __result, _Trivial());
            }
                  Copy 函數(shù)利用__type_traits判斷當(dāng)前的value_type是否有trival的賦值操作,如果是,則產(chǎn)生類__true_type的實(shí)例,編譯 時(shí)選擇__copy_trivial函數(shù)進(jìn)行memmove,效率最高。如果是non-trival的賦值操作,則另作處理,效率自然低些。__true_type和__false_type之所以是類,就因?yàn)镃++的函數(shù)重載是根據(jù)類型信息來(lái)的,不能依據(jù)參數(shù)值來(lái)判別。使用SGI STL時(shí),可以為自己的類定義__type_traits顯式特化版本,以求達(dá)到高效率。
            本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/budTang/archive/2008/05/06/2397013.aspx
            久久久久国产一区二区| 97久久久久人妻精品专区| 99久久精品国产一区二区 | 久久人人爽人人澡人人高潮AV | 91久久精品电影| 久久精品国产久精国产| 97久久久久人妻精品专区| 一本色道久久HEZYO无码| 久久久SS麻豆欧美国产日韩| 久久伊人亚洲AV无码网站| 久久99精品九九九久久婷婷| 91久久精品国产免费直播| 精品久久久久久无码免费| 久久国产香蕉一区精品| 色天使久久综合网天天 | 亚洲人成精品久久久久| 国内精品久久久久久99蜜桃| 久久精品国产亚洲沈樵| 久久一区二区免费播放| 久久综合狠狠综合久久综合88| 少妇人妻88久久中文字幕| 青青青青久久精品国产h| 99久久精品费精品国产| 久久精品国产免费观看三人同眠| 亚洲国产精品18久久久久久| 久久精品国产亚洲精品2020 | 中文成人无码精品久久久不卡 | 久久久精品2019免费观看| 久久久久久毛片免费播放| 伊人久久大香线蕉精品不卡| 久久亚洲精品人成综合网| 色综合久久夜色精品国产| 久久精品国产99国产精品澳门| 国内精品伊人久久久影院| 国产精品激情综合久久| 久久久久久国产精品免费无码| 精品久久久中文字幕人妻| 国产成人精品久久免费动漫| 久久久久久久亚洲Av无码| 国产伊人久久| 国产成人精品久久一区二区三区|