模板重載or編譯器的小技巧

來源:互聯網
上載者:User
最近在思考怎樣在C++中方便的實現委託,看了很多文章,但由於C++中對類非靜態成員函數指標的調用比較特殊,一直以來沒有找到很好的方法實現,直到最近在CodeProject上看到一篇關於C++中委託實現的方法,驚歎於作者高深的程式藝術,竟然可以重載模板類,通過同一個類來執行個體化多個不同參數個數,不同參數類型的函數指標,實現封裝調用函數,最終實現委託,原文串連為http://www.codeproject.com/cpp/FastDelegate.asp

俺試著學習了其中一些方法(只能看懂一部分 - -!),成果如下

類成員函數調用的實現:
    // 首先聲明該需要重載的模板類
    //  注意:此處的類型Signature非常特殊,在後面的定義中編譯器即把重載的所有型別宣告參數看做是一個參數
    //       編譯器會將<C, R ( T1, T2 ... TN ) >中的所有參數匹配到聲明中來
    //       其中:C對應於聲明中的C, 而R ( T1, T2 ... TN )看作是一個型別參數Signature
    //  只有這樣才能編譯通過,否則重載不成功,編譯器會報too many template arguments錯誤   
   
    // C為類類型, Signature為類成員函數指標類型( R (T1, T2 ... Tn) )
    template<class C, typename Signature>
    class MFunctor;   

    // N=0 沒有參數
    template<class C, typename R>
    class MFunctor<C, R ()>
    {
    public:
        MFunctor(C *pObj, R (C::* pFunc)())
            :m_pObj(pObj), m_pFunc(pFunc)
        {           
        }       
    public:
        R Invoke()
        {
            return (m_pObj->*m_pFunc)();
        }
    private:
        C * m_pObj;
        R (C::* m_pFunc)();
    };    // class TFunctor0

    // N=1 有一個參數
    template<class C, typename R, typename T>
    class MFunctor<C, R (T)>
    {
    public:
        MFunctor(C *pObj, R (C::* pFunc)(T))
            :m_pObj(pObj), m_pFunc(pFunc)
        {           
        }   
    public:
        R Invoke(T t)
        {
            return (m_pObj->*m_pFunc)(t);
        }
    private:
        C * m_pObj;
        R (C::* m_pFunc)(T);
    };    // class TFunctor1

    // N=2 有二個參數
    template<class C, typename R, typename T1, typename T2>
    class MFunctor<C, R (T1, T2)>
    {
    public:
        MFunctor(C *pObj, R (C::* pFunc)(T1, T2))
            :m_pObj(pObj), m_pFunc(pFunc)
        {           
        }       
    public:
        R Invoke(T1 t1, T2 t2)
        {
            return (m_pObj->*m_pFunc)(t1, t2);
        }
    private:
        C * m_pObj;
        R (C::* m_pFunc)(T1, T2);
    };    // class TFunctor2

封裝類成員函數以及普通函數的實現
    //////////////////////////////////////////////////////////////////////////
    // 封裝調用普通函數指標、類靜態函數指標以及類非靜態函數指標的實現
    // 其中只有類非靜態成員函數指標的調用比較特別,需要提供類實體才能實現調用,
    // 所以通過模板類MFunctor來封裝調用各種類成員函數   
    //////////////////////////////////////////////////////////////////////////

    // <typename Signature>中的Signature表示需要重載的特殊參數,
    // 比如<R ()>, <R (T1, T2 ... Tn)>, <C (R ())>, <C (R (T1, T2 ... Tn))>
    // 這個特殊參數比較特別,需要以這種形式才能編譯通過 type ( ... )
    template<typename Signature>
    class Functor;

    // N=0    //////////////////////////////////////////////////////////////////////////
    template<class C, typename R>
    class Functor<C (R ())>
    {
    public:
        Functor(MFunctor<C, R ()> tfunctor)
            :m_TFunctor(tfunctor)
        {
        }
       
        Functor(C *pObj, R (C::* pFunc)())
            :m_TFunctor(pObj, pFunc)
        {
        }
    public:
        R Invoke()
        {
            return m_TFunctor.Invoke();
        }
    private:
        MFunctor<C, R ()> m_TFunctor;
    };

    template<typename R>
    class Functor<R ()>
    {
    public:
        Functor(R (*pFunc)())
            :m_pFunc(pFunc)
        {
        }
    public:
        R Invoke()
        {
            return m_pFunc();
        }
    private:
        R (*m_pFunc)();
    };    // Functor0

    // N=1    //////////////////////////////////////////////////////////////////////////
    template<class C, typename R, typename T>
    class Functor<C (R (T))>
    {
    public:
        Functor(MFunctor<C, R (T)> tfunctor)
            :m_TFunctor(tfunctor)
        {
        }

        Functor(C *pObj, R (C::* pFunc)(T))
            :m_TFunctor(pObj, pFunc)
        {
        }
    public:
        R Invoke(T t)
        {
            return m_TFunctor.Invoke(t);
        }
    private:
        MFunctor<C, R (T)> m_TFunctor;
    };

    template<typename R, typename T>
    class Functor<R (T)>
    {
    public:
        Functor(R (*pFunc)(T))
            :m_pFunc(pFunc)
        {
        }
    public:
        R Invoke(T t)
        {
            return m_pFunc(t);
        }
    private:
        R (*m_pFunc)(T);
    };    // Functor1

    // N=2    //////////////////////////////////////////////////////////////////////////
    template<class C, typename R, typename T1, typename T2>
    class Functor<C (R (T1, T2))>
    {
    public:
        Functor(MFunctor<C, R (T1, T2)> tfunctor)
            :m_TFunctor(tfunctor)
        {
        }

        Functor(C *pObj, R (C::* pFunc)(T1, T2))
            :m_TFunctor(pObj, pFunc)
        {
        }
    public:
        R Invoke(T1 t1, T2 t2)
        {
            return m_TFunctor.Invoke(t1, t2);
        }
    private:
        MFunctor<C, R (T1, T2)> m_TFunctor;
    };

    template<typename R, typename T1, typename T2>
    class Functor<R (T1, T2)>
    {
    public:
        Functor(R (*pFunc)(T1, T2))
            :m_pFunc(pFunc)
        {
        }
    public:
        R Invoke(T1 t1, T2 t2)
        {
            return m_pFunc(t1, t2);
        }
    private:
        R (*m_pFunc)(T1, T2);
    };    // Functor2

這樣一類想要調用某個函數就非常容易了,例如
    Functor<void ()> functor0(&TestPrint);
    functor0.Invoke();   
    Functor<TestClass(void ())> cFunctor0(&ctest, &TestClass::TestPrint);
    cFunctor0.Invoke();

雖然這樣實現代碼非常漂亮,但是卻有個很大的缺陷,因為R (T1, T2 ... Tn)這樣的參數定義非常新穎,只有最新的編譯器才支援(vs2005編譯通過!),所以留下一個疑惑!這究竟是真正的函數重載實現呢,還是特殊編譯器的一個動態編譯技巧?本人在網上還沒找到相關的具體說明,希望瞭解的牛人路過指點下,如果能給出詳細說明的串連,俺就先拜謝了!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.