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

            我們知道在C++模板編程中如果我們特化或是偏特化某個(gè)模板類, 我們需要重寫整個(gè)模板類中的所有函數(shù), 但是這些代碼通常是非常相似的, 甚至在某些情況下可能只有一兩個(gè)函數(shù)會(huì)不一樣,其他函數(shù)都是一樣的。在這種情況下,同時(shí)存在多份相同的代碼,對(duì)我們維護(hù)這些代碼是非常不利的, 我們最好只需要特化其中不一樣的那個(gè)函數(shù)。

            比如下面這個(gè)模板類:

             

            template<typename T, unsigned B>
            struct Base
            {
                //other function
                //....
                void Func(){ cout << "primary function" << endl; }
            };
            void test1()
            {
                Base<int1> a;
                a.Func();
                Base<int16> b;
                b.Func();
            }
            int main()
            {
                 test1();
            }

             

             

            只有當(dāng)B等于16時(shí), Func這個(gè)函數(shù)需要特化, 但是其他函數(shù)無(wú)論什么情況下都是一樣的。

            下面是我們的一些可能解決方案:

            方法1:

             

            template<typename T>
            struct Base<T, 16>
            {
                //other function
                //....
                void Func(){ cout << "specialization function" << endl; }
            };

             

            點(diǎn)評(píng):通過(guò)偏特化實(shí)現(xiàn),需要重寫所有的類成員方法。

             

            方法2:

             

            template<typename T, unsigned B>
            struct Base
            {
                //other function
                //....
                void Func()
                {
                    if(B == 16)
                    {
                        cout << "primary function" << endl;
                    }
                    else
                    {
                        cout << "specialization function" << endl;
                    }
                }
            };

             

            點(diǎn)評(píng): 通過(guò)運(yùn)行時(shí)判斷, 容易理解,但是相對(duì)低效。

             

            方法3:

             

            template<typename T, unsigned B>
            struct Base
            {
                //other function
                //....
                void Func()
                {
            #if B!=16
                        cout << "primary function" << endl;
            #else
                        cout << "specialization function" << endl;
            #endif
                }
            };

             

            點(diǎn)評(píng): 試圖通過(guò)預(yù)編譯來(lái)實(shí)現(xiàn),但是這個(gè)方法是錯(cuò)誤的。C++模板編譯包括預(yù)編譯,語(yǔ)法檢查,模板實(shí)例化等階段,在預(yù)編譯階段模板參數(shù)都還沒(méi)有實(shí)例化呢。

             

            方法4:

             

            template<typename T, unsigned B>
            struct Base
            {
                //other function
                //....
                template<unsigned S>
                struct FuncObj
                {
                    void operator()()
                    {
                        cout<<"primary function"<<endl;
                    }
                };
                template<>
                struct FuncObj<16>
                {
                    void operator()()
                    {
                        cout<<"specialization function"<<endl;
                    }
                };
                FuncObj<B> Func;
            };

             

            點(diǎn)評(píng): 通過(guò)成員類以防函數(shù)的形式特化, 增加了類成員變量。

             

            方法5:

             

            template<typename T, unsigned B>
            struct Base
            {
                //other function
                //....
                template<unsigned N>
                void FuncImpl()
                {
                    cout<<"primary function"<<endl;
                }
                template<>
                void FuncImpl<16>()
                {
                    cout<<"specialization function"<<endl;
                }
                void Func()
                {
                    FuncImpl<B>();
                }
            };

             

            點(diǎn)評(píng):通過(guò)類成員模板函數(shù)特化來(lái)實(shí)現(xiàn)。

             

            方法6:

             

            template<typename T, unsigned B>
            struct Base
            {
                //other function
                //....
                template<unsigned N> 
                class Int2Type
                {
                    enum { value = N };
                };
                template<unsigned V>
                void FuncImpl(const Int2Type<V>)
                {
                    cout<<"primary function"<<endl;
                }
                void FuncImpl(const Int2Type<16>)
                {
                    cout<<"specialization function"<<endl;
                }
                void Func()
                {
                    FuncImpl(Int2Type<B>());
                }
            };

             

            點(diǎn)評(píng): 通過(guò)將int根據(jù)值的不同轉(zhuǎn)成不同的類型,然后通過(guò)函數(shù)重載實(shí)現(xiàn)。

             

            方法7:

             

            namespace
            {
                template <bool,typename T,typename> struct conditional { typedef T type; };
                template <typename T,typename U> struct conditional<false,T,U> {typedef U type; };
            }
            template<class T, unsigned B>
            struct Base
            {
                //other function
                //....

                void Func ()
                {
                    typedef typename ::conditional<B!=16,primary_t,spec_t>::type type;
                    Func_impl(type());
                }
            private:
                struct primary_t { };
                struct spec_t    { };
                void Func_impl (primary_t) { std::cout << "primary function" << std::endl; }
                void Func_impl (spec_t   ) { std::cout << "specialization function" << std::endl; }
            };

             

            點(diǎn)評(píng): 和方法6類似,通過(guò)函數(shù)重載實(shí)現(xiàn)

             

            方法8:

             namespace

             {
                template <bool,typename T = voidstruct enable_if { typedef T type; };
                template <typename T> struct enable_if<true,T> {};
            }
            template<class T, unsigned B>
            struct Base
            {
                //other function
                //....

                template <unsigned N>
                typename ::enable_if<16!=N>::type
                    FuncImpl () { std::cout << "primary function" << std::endl; }
                template <unsigned N>
                typename ::enable_if<16==N>::type
                    FuncImpl () { std::cout << "specialization function" << std::endl; }
                void Func() {
                    FuncImpl<B>();
                }
            };

            點(diǎn)評(píng):通過(guò)enable_if, 利用SFINAE實(shí)現(xiàn)。

             

            我們可以看到根據(jù)編譯時(shí)模板參數(shù)int值的不同,我們重寫模板類的某個(gè)成員函數(shù)的方法是多種多樣的。針對(duì)上面這種情況,個(gè)人其實(shí)最推薦方法2,我們沒(méi)必要把簡(jiǎn)單的問(wèn)題復(fù)雜化。

             

            下面我們考慮另外一個(gè)需求, 當(dāng)模板類的某個(gè)參數(shù)是某種類型時(shí), 我們要求特化其中的一個(gè)成員函數(shù):

             

            template<typename T1, typename T2>
            struct Base
            {
                //other function
                //....
                void Func(){ cout << "primary function" << endl; }
            };
            void test2()
            {
                Base<intint> a;
                a.Func();
                Base<intstring> b;
                b.Func();
            }
            int main()
            {
                test2();
            }

             

            要求上面的模板類如果T2 是string類型, 我們要求對(duì)Func特殊重寫,其他的成員函數(shù)無(wú)論什么情況實(shí)現(xiàn)都是一樣的。

            有了上面的那個(gè)例子的實(shí)現(xiàn)經(jīng)驗(yàn), 對(duì)這個(gè)問(wèn)題我們解決就方便多了。

             

            方法1:

             

            template<typename T1, typename T2>
            struct Base
            {
                //other function
                //....
                void Func()
                {
                    if(typeid(std::string) == typeid(T2))
                    {
                        cout<<"specialization function"<<endl;
                    }
                    else
                    {
                        cout << "primary function" << endl; 
                    }
                }
            };

             

            點(diǎn)評(píng):通過(guò)運(yùn)行時(shí)類型識(shí)別(RTTI)實(shí)現(xiàn),需要打開相關(guān)編譯選項(xiàng),并且低效。

             

            方法2:

             

            template<typename T1, typename T2>
            struct Base
            {
                //other function
                //....
                template<typename T>
                void FuncImpl()
                {
                    cout << "primary function" << endl; 
                }
                template<>
                void FuncImpl<string>()
                {
                    cout << "specialization function" << endl; 
                }
                void Func()
                {
                    FuncImpl<T2>();
                }
            };

             

            點(diǎn)評(píng):通過(guò)成員函數(shù)特化實(shí)現(xiàn)

             

            方法3:

             

            template<typename T1, typename T2>
            struct Base
            {
                //other function
                //....
                template<typename T> 
                class Type2Type
                {
                    typedef T type;
                };
                template<typename T>
                void FunImpl(const Type2Type<T>)
                {
                    cout << "primary function" << endl; 
                }
                template<typename T>
                void FunImpl(const Type2Type<string>)
                {
                    cout << "specialization function" << endl; 
                }
                void Func()
                {
                    FunImpl<T2>(Type2Type<T2>());
                }
            };

             

            點(diǎn)評(píng): 通過(guò)函數(shù)重載實(shí)現(xiàn)

             

            方法4:

             

            template<typename T>
            struct IsString
            {
                enum { value = false };
            };
            template<>
            struct IsString<string>
            {
                enum { value = true };
            };
            template<typename T1, typename T2>
            struct Base
            {
                //other function
                //....
                void Func()
                { 
                    if(IsString<T2>::value)
                    {
                        cout << "specialization function" << endl; 
                    }
                    else
                    {
                        cout << "primary function" << endl; 
                    }
                }
            };

             

            點(diǎn)評(píng): 通過(guò)編譯時(shí)類型判斷實(shí)現(xiàn)。

             

            方法5:

             

            template<typename T3,  typename T4>
            struct must_be_same_type
            {
                enum { ret = 0 };
            };
            template<>
            struct must_be_same_type<stringstring>
            {
                enum { ret = 1 };
            };
            template < typename T1,typename T2 >
            class Base{
            public:
                //other function
                //....
                void Func(){
                    if(must_be_same_type<T2, string>::ret)
                    {
                        cout << "specialization function" << endl; 
                    }
                    else
                    {
                        cout << "primary function" << endl; 
                    }
                }
            };

             

            點(diǎn)評(píng): 和方法4類似, 是不過(guò)實(shí)現(xiàn)方式不一樣。

             

            最后,探討下我自己遇到的問(wèn)題, 我們?cè)趯懸粋€(gè)事件委托(delegate)類,大概如下:

             

            template<typename return_type, typename first_type, typename second_type>
            class CEvent 
            {
            public:
                //other function
                //....
                return_type operator()(first_type p1, second_type p2)
                {
                    return_type ret = return_type();
                    //...
                    //ret = invoker(p1, p2);
                    return ret;
                }
            };
            void test3()
            {
                CEvent<intintint> e1;
                e1(12);
                CEvent<voidintint> e2;
                e2(12);
            }
            int main()
            {
                test3();
            }

             

            我們可以看到,當(dāng)return_type是void時(shí), 因?yàn)闆](méi)有返回值,上面的代碼會(huì)編譯失敗,因此我們只能偏特化這種情況:

             

            template<typename first_type, typename second_type>
            class CEvent<void, first_type, second_type>
            {
            public:
                //other function
                //....
                void operator()(first_type p1, second_type p2)
                {
                    //...
                    //invoker(p1, p2);
                    return;
                }
            };

             

            但是,我們會(huì)發(fā)現(xiàn)只有這個(gè)operator()函數(shù)是需要根據(jù)return_type特殊對(duì)待的,其他函數(shù)永遠(yuǎn)都是一樣的。

            我們現(xiàn)在的問(wèn)題就是如何只特化這個(gè)函數(shù)。

             

            首先我們會(huì)想到如下的實(shí)現(xiàn)方法:

             

            template<typename T>
            struct IsVoid
            {
                enum { value = false };
            };
            template<>
            struct IsVoid<void>
            {
                enum { value = true };
            };
            template<typename return_type, typename first_type, typename second_type>
            class CEvent 
            {
            public:
                other function
                ....
                return_type operator()(first_type p1, second_type p2)
                {
                    if(IsVoid<return_type>::value)
                    {
                        cout << "return type is void" << endl;
                        //...
                        //invoker(p1, p2);
                    }
                    else
                    {
                        cout << "return type is not void" << endl;
                        return_type ret = return_type();
                        //...
                        //ret = invoker(p1, p2);
                        return ret;
                    }
                }
            };

             

            但是我們很快會(huì)發(fā)現(xiàn)這種情況下if語(yǔ)句被編譯進(jìn)去了, 所以return_type是void的情況下還是會(huì)編譯失敗。

            我們要解決的問(wèn)題就是如何把這個(gè)if語(yǔ)句變成函數(shù)重載,于是我們想到如下實(shí)現(xiàn):

             

            template<typename T>
            struct IsVoid
            {
                enum { value = false };
            };
            template<>
            struct IsVoid<void>
            {
                enum { value = true };
            };
            template<int v>
            class Int2Type
            {
                enum {value = v };
            };
            template<typename return_type, typename first_type, typename second_type>
            class CEvent 
            {
            public:
                //other function
                //....
                return_type InvokerImpl(first_type p1, second_type p2, Int2Type<true>)
                {
                    cout << "return type is void" << endl;
                    //...
                    //invoker(p1, p2);
                }
                return_type InvokerImpl(first_type p1, second_type p2, Int2Type<false>)
                {
                    cout << "return type is not void" << endl;
                    return_type ret = return_type();
                    //...
                    //ret = invoker(p1, p2);
                    return ret;
                }
                return_type operator()(first_type p1, second_type p2)
                {
                    return InvokerImpl(p1, p2, Int2Type<IsVoid<return_type>::value>());
                }
            };

             

            上面的實(shí)現(xiàn)首先通過(guò)編譯時(shí)類型識(shí)別,然后再把識(shí)別后相應(yīng)的bool值轉(zhuǎn)成不同類型, 最后再利用不同類型函數(shù)重載實(shí)現(xiàn)。

             

            最后總結(jié)下,我們可以看到,從編譯時(shí)到運(yùn)行時(shí),從面向?qū)ο蟮狡胀ǚ盒途幊淘俚侥0逶幊蹋珻++復(fù)雜得讓人無(wú)語(yǔ), 也強(qiáng)大得讓人無(wú)語(yǔ), 而且C++語(yǔ)言本身是在不斷發(fā)展的(C++11), 同一問(wèn)題在C++中往往有多種解決方案,這些解決方案有的簡(jiǎn)單,有的復(fù)雜,有的高效, 也有的低效, 而我們的目標(biāo)就是利用C++這把利器尋找簡(jiǎn)單而高效的解決方案。

             

            注:本人初學(xué)C++ templates編程,如有錯(cuò)誤,歡迎指正。

                  參考資料:http://bbs.csdn.net/topics/390116038

                                http://bbs.csdn.net/topics/270041821

            posted on 2013-02-14 20:31 Richard Wei 閱讀(5402) 評(píng)論(10)  編輯 收藏 引用 所屬分類: STL&GP

            FeedBack:
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-14 21:19 | lwch
            Orz.....  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-14 21:31 | Richard Wei
            @lwch
            不懂, 什么意思?
            不過(guò)看了你的博客,學(xué)習(xí)了 ^_^   回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-15 20:36 | lwch
            @Richard Wei
            膜拜ing.....  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-15 20:41 | Richard Wei
            @lwch
            慚愧, 雖然工作好多年,最近才開始研究模板,準(zhǔn)備稍微深入一下。  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-19 08:42 | 歲月漫步
            真的沒(méi)看明白什么意思  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-19 09:01 | Richard Wei
            @歲月漫步
            那就看看這個(gè)http://bbs.csdn.net/topics/390116038  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-22 09:34 | 永遇樂(lè)
            又讓我在這里復(fù)習(xí)了一下SFINAE,謝謝  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-23 08:28 | a_very_big_graywolf
            樓主真蛋疼,精神值得學(xué)習(xí)。
            只想說(shuō)一句,兩個(gè)需求可以用一個(gè)更簡(jiǎn)單的辦法來(lái)解決:
            調(diào)整程序設(shè)計(jì),用繼承來(lái)規(guī)避只特化某個(gè)成員函數(shù)的方法。
            這樣就用繼承的優(yōu)勢(shì)來(lái)減少代碼重復(fù)量了。
            僅供參考  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-02-23 16:28 | Richard Wei
            @a_very_big_graywolf
            只是總結(jié), 以后再用到會(huì)方便一些。
            不錯(cuò), 前2個(gè)需求也可以用繼承來(lái)實(shí)現(xiàn), 但是如果該特化函數(shù)基類內(nèi)部有調(diào)用,就可能要搞成虛函數(shù)了。  回復(fù)  更多評(píng)論
              
            # re: 在C++范型編程中如何只特化類的一個(gè)成員函數(shù)
            2013-03-04 16:22 | tb
            膜拜ing..... 太強(qiáng)了   回復(fù)  更多評(píng)論
              
            91久久精一区二区三区大全| 一本久道久久综合狠狠躁AV| 91精品国产综合久久精品| 国产精品美女久久久| 精品久久久无码中文字幕| 欧美一区二区久久精品| 久久精品中文字幕无码绿巨人| 国产成人精品久久综合| 一本一本久久a久久综合精品蜜桃| 99热成人精品免费久久| 三上悠亚久久精品| 国产精品久久久香蕉| 国产精品成人无码久久久久久 | 久久精品无码一区二区三区日韩| 亚洲精品tv久久久久久久久久| 99久久人妻无码精品系列| 麻豆av久久av盛宴av| 国内精品免费久久影院| 国产亚洲欧美成人久久片| 国产成人精品久久| 少妇无套内谢久久久久| 亚洲国产精品综合久久一线| 99久久国产亚洲高清观看2024| 国产精品美女久久久m| 精品久久亚洲中文无码| 免费精品国产日韩热久久| 色99久久久久高潮综合影院| 国产精品gz久久久| 亚洲成色999久久网站| 免费国产99久久久香蕉| 7777久久亚洲中文字幕| 久久国产精品99精品国产987| 91精品国产91久久久久福利| 99热成人精品热久久669| 国产精品久久一区二区三区 | 青草影院天堂男人久久| 午夜不卡888久久| 老司机午夜网站国内精品久久久久久久久| 久久99精品国产99久久6男男| a级毛片无码兔费真人久久| 国产免费久久久久久无码|