青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

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

比如下面這個模板類:

 

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();
}

 

 

只有當B等于16時, Func這個函數需要特化, 但是其他函數無論什么情況下都是一樣的。

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

方法1:

 

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

 

點評:通過偏特化實現,需要重寫所有的類成員方法。

 

方法2:

 

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

 

點評: 通過運行時判斷, 容易理解,但是相對低效。

 

方法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
    }
};

 

點評: 試圖通過預編譯來實現,但是這個方法是錯誤的。C++模板編譯包括預編譯,語法檢查,模板實例化等階段,在預編譯階段模板參數都還沒有實例化呢。

 

方法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;
};

 

點評: 通過成員類以防函數的形式特化, 增加了類成員變量。

 

方法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>();
    }
};

 

點評:通過類成員模板函數特化來實現。

 

方法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>());
    }
};

 

點評: 通過將int根據值的不同轉成不同的類型,然后通過函數重載實現。

 

方法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; }
};

 

點評: 和方法6類似,通過函數重載實現

 

方法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>();
    }
};

點評:通過enable_if, 利用SFINAE實現。

 

我們可以看到根據編譯時模板參數int值的不同,我們重寫模板類的某個成員函數的方法是多種多樣的。針對上面這種情況,個人其實最推薦方法2,我們沒必要把簡單的問題復雜化。

 

下面我們考慮另外一個需求, 當模板類的某個參數是某種類型時, 我們要求特化其中的一個成員函數:

 

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類型, 我們要求對Func特殊重寫,其他的成員函數無論什么情況實現都是一樣的。

有了上面的那個例子的實現經驗, 對這個問題我們解決就方便多了。

 

方法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; 
        }
    }
};

 

點評:通過運行時類型識別(RTTI)實現,需要打開相關編譯選項,并且低效。

 

方法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>();
    }
};

 

點評:通過成員函數特化實現

 

方法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>());
    }
};

 

點評: 通過函數重載實現

 

方法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; 
        }
    }
};

 

點評: 通過編譯時類型判斷實現。

 

方法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; 
        }
    }
};

 

點評: 和方法4類似, 是不過實現方式不一樣。

 

最后,探討下我自己遇到的問題, 我們在寫一個事件委托(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();
}

 

我們可以看到,當return_type是void時, 因為沒有返回值,上面的代碼會編譯失敗,因此我們只能偏特化這種情況:

 

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;
    }
};

 

但是,我們會發現只有這個operator()函數是需要根據return_type特殊對待的,其他函數永遠都是一樣的。

我們現在的問題就是如何只特化這個函數。

 

首先我們會想到如下的實現方法:

 

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;
        }
    }
};

 

但是我們很快會發現這種情況下if語句被編譯進去了, 所以return_type是void的情況下還是會編譯失敗。

我們要解決的問題就是如何把這個if語句變成函數重載,于是我們想到如下實現:

 

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>());
    }
};

 

上面的實現首先通過編譯時類型識別,然后再把識別后相應的bool值轉成不同類型, 最后再利用不同類型函數重載實現。

 

最后總結下,我們可以看到,從編譯時到運行時,從面向對象到普通泛型編程再到模板元編程,C++復雜得讓人無語, 也強大得讓人無語, 而且C++語言本身是在不斷發展的(C++11), 同一問題在C++中往往有多種解決方案,這些解決方案有的簡單,有的復雜,有的高效, 也有的低效, 而我們的目標就是利用C++這把利器尋找簡單而高效的解決方案。

 

注:本人初學C++ templates編程,如有錯誤,歡迎指正。

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

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

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

FeedBack:
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-14 21:19 | lwch
Orz.....  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-14 21:31 | Richard Wei
@lwch
不懂, 什么意思?
不過看了你的博客,學習了 ^_^   回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-15 20:36 | lwch
@Richard Wei
膜拜ing.....  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-15 20:41 | Richard Wei
@lwch
慚愧, 雖然工作好多年,最近才開始研究模板,準備稍微深入一下。  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-19 08:42 | 歲月漫步
真的沒看明白什么意思  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-19 09:01 | Richard Wei
@歲月漫步
那就看看這個http://bbs.csdn.net/topics/390116038  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-22 09:34 | 永遇樂
又讓我在這里復習了一下SFINAE,謝謝  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-23 08:28 | a_very_big_graywolf
樓主真蛋疼,精神值得學習。
只想說一句,兩個需求可以用一個更簡單的辦法來解決:
調整程序設計,用繼承來規避只特化某個成員函數的方法。
這樣就用繼承的優勢來減少代碼重復量了。
僅供參考  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-02-23 16:28 | Richard Wei
@a_very_big_graywolf
只是總結, 以后再用到會方便一些。
不錯, 前2個需求也可以用繼承來實現, 但是如果該特化函數基類內部有調用,就可能要搞成虛函數了。  回復  更多評論
  
# re: 在C++范型編程中如何只特化類的一個成員函數
2013-03-04 16:22 | tb
膜拜ing..... 太強了   回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久gogo国模裸体人体| 欧美高清一区二区| 欧美 日韩 国产在线| 久久精品夜色噜噜亚洲aⅴ| 午夜亚洲性色视频| 欧美在线免费看| 久久久一区二区| 女人香蕉久久**毛片精品| 亚洲高清免费| 亚洲激情网站| 亚洲美女区一区| 亚洲综合精品一区二区| 久久精品99久久香蕉国产色戒| 午夜精品久久久久久久久| 久久久久国产精品一区三寸| 每日更新成人在线视频| 欧美激情第二页| 国产精品永久入口久久久| 一区在线免费| 日韩视频在线一区二区| 亚洲午夜国产一区99re久久| 久久大逼视频| 亚洲国产一区二区三区在线播 | 国产精品亚洲人在线观看| 国产午夜精品在线| 亚洲三级网站| 欧美专区在线| 亚洲欧洲日韩综合二区| 午夜精品久久久久久久99热浪潮| 久久九九国产精品| 国产精品久久久久aaaa| 亚洲国产天堂网精品网站| 亚洲免费小视频| 一区二区三区视频在线播放| 国产午夜精品一区二区三区欧美| 亚洲欧洲另类国产综合| 亚洲午夜小视频| 噜噜爱69成人精品| 亚洲午夜一区二区三区| 麻豆成人精品| 黄色成人免费网站| 亚洲免费中文字幕| 亚洲免费激情| 免费观看一级特黄欧美大片| 国产三级精品在线不卡| 在线性视频日韩欧美| 免费看黄裸体一级大秀欧美| 一区二区三区视频观看| 暖暖成人免费视频| 亚洲电影免费在线 | 一区二区三区导航| 欧美精品二区| 99综合视频| 亚洲人成毛片在线播放| 久久人91精品久久久久久不卡 | 欧美日韩国产精品一区| 在线观看视频日韩| 亚洲人成绝费网站色www| 久久久国产精品一区| 亚洲深夜激情| 欧美性猛交xxxx乱大交蜜桃| 日韩亚洲欧美综合| 亚洲黄一区二区| 男人插女人欧美| 亚洲国产日韩欧美在线动漫| 巨乳诱惑日韩免费av| 午夜精品久久久99热福利| 国产精品一区一区三区| 久久都是精品| 欧美一区二区啪啪| 在线观看日韩| 亚洲乱码国产乱码精品精| 欧美日韩1080p| 亚洲综合视频网| 欧美亚洲自偷自偷| 国产日韩欧美不卡| 麻豆精品一区二区av白丝在线| 久久精品国产精品| 亚洲国语精品自产拍在线观看| 亚洲第一中文字幕在线观看| 久热精品视频在线观看一区| 亚洲日本久久| 中文日韩电影网站| 国产一在线精品一区在线观看| 久久全国免费视频| 欧美国产日韩a欧美在线观看| 一区二区三区日韩在线观看 | 国产精品国产成人国产三级| 久久久久久有精品国产| 在线观看欧美一区| 亚洲美女色禁图| 国产一区二区三区自拍| 欧美jizz19hd性欧美| 欧美大色视频| 欧美中文字幕| 欧美高清在线观看| 久久久久久久国产| 欧美极品影院| 久久久久成人精品免费播放动漫| 麻豆精品视频在线观看| 亚洲免费在线看| 免费欧美在线| 久久激情五月丁香伊人| 欧美成人有码| 久久综合伊人77777麻豆| 欧美日韩国产综合网 | 亚洲精品日韩在线观看| 国产女主播视频一区二区| 亚洲第一福利视频| 国产欧美日韩视频一区二区三区| 亚洲第一毛片| 精品动漫3d一区二区三区免费| 99国产精品久久久久久久| 国产真实乱偷精品视频免| 亚洲乱码精品一二三四区日韩在线| 国产一区二区av| 亚洲天堂av图片| 99热这里只有成人精品国产| 久久国产精品久久久久久久久久| 一本色道久久综合亚洲精品高清| 久久久久免费视频| 久久不射中文字幕| 国产精品久久一级| 洋洋av久久久久久久一区| 亚洲精品午夜精品| 欧美 日韩 国产在线| 能在线观看的日韩av| 国产亚洲精品bt天堂精选| 夜夜狂射影院欧美极品| 亚洲精品一区二区三区不| 久热国产精品| 欧美高清一区| 亚洲高清123| 美国十次成人| 亚洲国产精品成人精品| 亚洲国产高清在线观看视频| 久久久久久网站| 老司机成人在线视频| 狠狠色丁香久久综合频道| 久久成人在线| 久久综合精品国产一区二区三区| 国产人成精品一区二区三| 亚洲一区二区精品在线观看| 亚洲一区亚洲| 国产精品日韩欧美大师| 亚洲欧美日本精品| 西瓜成人精品人成网站| 国产精品自拍一区| 久久精品国产综合| 欧美成人一区二区在线| 亚洲国产日韩一区| 欧美激情小视频| 亚洲欧洲一区二区在线播放| 伊人久久大香线蕉综合热线| 亚洲欧美日韩综合国产aⅴ| 国产精品h在线观看| 中文在线一区| 久久国产精品72免费观看| 欧美视频一区二区| 欧美一区二区三区日韩| 模特精品裸拍一区| 亚洲精品视频一区| 国产精品久久久999| 亚洲欧美综合精品久久成人 | 亚洲精选在线观看| 亚洲女同精品视频| 国产一区二区三区日韩欧美| 久久午夜电影网| 亚洲免费黄色| 久久久久高清| 亚洲美女在线一区| 国产精品入口日韩视频大尺度| 久久精品男女| 亚洲精品综合久久中文字幕| 久久精品久久99精品久久| 亚洲精选国产| 国内免费精品永久在线视频| 欧美精品久久一区| 欧美在线视频观看| 亚洲美女黄网| 美日韩精品免费| 亚洲在线网站| 亚洲人妖在线| 国产亚洲一区二区三区在线观看| 欧美电影在线免费观看网站 | 欧美精品大片| 久久99伊人| 在线性视频日韩欧美| 蜜桃av一区二区三区| 宅男噜噜噜66一区二区66| 樱桃视频在线观看一区| 欧美日韩一区二区三区在线观看免| 欧美一区二区在线看| 亚洲免费高清| 亚洲国产精品传媒在线观看 | 国产老肥熟一区二区三区| 久久视频一区| 久久成人精品无人区| 中国女人久久久| 亚洲看片网站|