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

            天秤座的唐風(fēng)

            總會(huì)有一個(gè)人需要你的分享~!- 唐風(fēng) -

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              13 隨筆 :: 0 文章 :: 69 評(píng)論 :: 0 Trackbacks

            作者:唐風(fēng)

            原載:www.cnblogs.com/liyiwen

             

            關(guān)于類(lèi)型擦除,在網(wǎng)上搜出來(lái)的中文資料比較少,而且一提到類(lèi)型擦除,檢索結(jié)果里就跑出很多 Java 和 C# 相關(guān)的文章來(lái)(它們實(shí)現(xiàn)“泛型”的方式)。所以,這一篇我打算寫(xiě)得稍微詳細(xì)一點(diǎn)。 注意,這是一篇讀書(shū)筆記(《C++ template metaprogramming》第9.7小節(jié)和《C++ テンプレートテクニック》第七章),里面的例子都來(lái)自原書(shū)。


            在 C++ 中,編譯器在編譯期進(jìn)行的靜態(tài)類(lèi)型檢查是比較嚴(yán)格的,但有時(shí)候我們卻希望能“避過(guò)”這樣的類(lèi)型檢查,以實(shí)現(xiàn)更靈活的功能,同時(shí)又盡量地保持類(lèi)型安全。聽(tīng)起來(lái)很矛盾,而且貌似很難辦到。但其實(shí) C++ 的庫(kù)里已經(jīng)有很多這樣的應(yīng)用了。比如,著名的 boost::function 和 boost::any 。當(dāng)我們定義一個(gè) function<void(int)> fun 對(duì)象,則 fun 即可以存儲(chǔ)函數(shù)指針,又可以存儲(chǔ)函數(shù)對(duì)象,注意,這兩者是不同“類(lèi)型”的,而且函數(shù)對(duì)象可以是無(wú)限種類(lèi)型的,但這些不同類(lèi)型的“東西”都可以存在同一類(lèi)型的對(duì)象 fun 中,對(duì) fun 來(lái)說(shuō),它關(guān)心的只是存儲(chǔ)的“對(duì)象”是不是“可以按某種形式(如void(int))來(lái)調(diào)用”,而不關(guān)心這個(gè)“對(duì)象”是什么樣的類(lèi)型。有了 function 這樣的庫(kù),在使用回調(diào)和保存可調(diào)用“對(duì)象”的時(shí)候,我們就可以寫(xiě)出更簡(jiǎn)單且更好用的代碼來(lái)。再舉一個(gè)例子,boost::any 庫(kù)。any 可以存儲(chǔ)任何類(lèi)型的“對(duì)象”,比如 int ,或是你自己定義的類(lèi) MyCla 的對(duì)象。這樣我們就可以使一個(gè)容器(比如 vector<boost::any> )來(lái)存儲(chǔ)不同類(lèi)型的對(duì)象了。

            這些庫(kù)所表現(xiàn)出來(lái)的行為,就是這篇文章中要提到的類(lèi)型擦除,類(lèi)型擦除可以達(dá)到下面兩個(gè)目的:

            • 用類(lèi)型 S 的接口代表一系列類(lèi)型 T 的的共性。
            • 如果 s 是 S 類(lèi)型的變量,那么,任何 T 類(lèi)型的的對(duì)象都可以賦值給s。

            好了,下面我們具體地看看類(lèi)型擦除是怎么回事,在這個(gè)過(guò)程中,我們先以 any 這個(gè)類(lèi)為依托來(lái)解釋?zhuān)ㄒ驗(yàn)樗容^“簡(jiǎn)單”,要解釋的額外的東西比較少)。

            any 這個(gè)類(lèi)需要完成的主要任務(wù)是:1. 存儲(chǔ)任何類(lèi)型的變量 2. 可以相互拷貝 3. 可以查詢(xún)所存變量的類(lèi)型信息 4. 可以轉(zhuǎn)化回原來(lái)的類(lèi)型(any_cast<>)

            對(duì)于其中,只要說(shuō)明1和2 ,就能把類(lèi)型擦除的做法展示出來(lái)了,所以,我們這里只實(shí)現(xiàn)一個(gè)簡(jiǎn)單的,有1、2、3功能的any類(lèi)(3是為了驗(yàn)證)。

            首先,寫(xiě)個(gè)最簡(jiǎn)單的“架子”出來(lái):

            class my_any { 
                ?? content_obj; 
            public: 
                template <typename T> 
                my_any(T const& a_right); 
            }; 

            這里,由于 my_any 的拷貝構(gòu)造函數(shù)使用的是模板函數(shù),因此,我們可以任何類(lèi)型的對(duì)象來(lái)初始化,并把該對(duì)象的復(fù)本保存在 content_obj 這個(gè)數(shù)據(jù)成員中。那么,問(wèn)題是,content_obj 用什么類(lèi)型好呢?

            首先我們會(huì)想到,給 class 加個(gè)模板參數(shù) T ,然后……,不用然后了,這樣的話(huà),使用者需要寫(xiě)這樣的代碼:

            my_any<someType> x = y;

            不同的 y 會(huì)創(chuàng)造出不同類(lèi)型的 x 對(duì)象,完全不符合我們要將不同類(lèi)型對(duì)象賦給同一類(lèi)型對(duì)象的初衷。接著,我們會(huì)想到用 void *(C 式的泛型手法啊……),但這樣的話(huà),我們就會(huì)完全地丟失原對(duì)象的信息,使得后面一些操作(拷貝、還原等)變得很困難,那么,再配合著加入一些變量用于保存原對(duì)象信息?你是說(shuō)用類(lèi)似“反射”的能力?好吧,我只好說(shuō),我以為 C++ 不存在原生的反射能力,以我淺薄的認(rèn)識(shí),我只知道像 MFC 式的侵入式手法……,嗯,此路不通。

            這個(gè)困境的原因在于,在C++ 的類(lèi)中,除了類(lèi)模板參數(shù)之外,無(wú)法在不同的成員(函數(shù)、數(shù)據(jù)成員)之間共享類(lèi)型信息。在這個(gè)例子中,content_obj 無(wú)法得知構(gòu)造函數(shù)中的 T 是什么類(lèi)型。所以類(lèi)型無(wú)法確定。

            為了妥善保存原對(duì)象復(fù)本,我們定義兩個(gè)輔助類(lèi),先上代碼(來(lái)自 boost::any 的原碼):

            class placeholder 
            { 
            public: // structors 
                virtual ~placeholder()      { 
                } 
            public: // queries 
                virtual const std::type_info & type() const = 0; 
                virtual placeholder * clone() const = 0; 
            }; 
            
            template<typename ValueType> 
            class holder : public placeholder 
            { 
            public: // structors 
                holder(const ValueType & value): held(value) 
                { 
                } 
            public: // queries 
                virtual const std::type_info & type() const { 
                    return typeid(ValueType); 
                } 
                virtual placeholder * clone() const { 
                    return new holder(held); 
                } 
            public: // representation 
                ValueType held; 
            }; 

            首先,定義了一個(gè)基類(lèi) placeholder ,它是一個(gè)非模板的抽象類(lèi),這個(gè)抽象類(lèi)的兩個(gè)接口是用來(lái)抽取對(duì)保存在 my_any 中的各種類(lèi)型對(duì)象的共性的,也就是,我們需要對(duì)被保存在 my_any 中的數(shù)據(jù)進(jìn)行拷貝和類(lèi)型查詢(xún)。

            然后用一個(gè)模板類(lèi) holder 類(lèi)繼承 placeholder 類(lèi),這個(gè)(類(lèi))派生類(lèi)實(shí)現(xiàn)了基類(lèi)的虛函數(shù),并保存了相關(guān)的數(shù)據(jù)。注意,派生類(lèi)的數(shù)據(jù)成員的類(lèi)型是 ValueType,也就是完整的原對(duì)象類(lèi)型,由于它是個(gè)模板類(lèi),各個(gè)類(lèi)成員之間可以共享類(lèi)模板參數(shù)的信息,所以,可以方便地用原數(shù)據(jù)類(lèi)型來(lái)進(jìn)行各種操作。

            有了這兩個(gè)輔助類(lèi),我們就可以這樣寫(xiě) my_any 了:

            class My_any
            {
                placeholder * content_obj;
            public:
                template <typename T>
                My_any(T const& a_right):content_obj(new T(a_right))
                {}
            
                template <typename T>
                My_any & operator = (T const& a_right) {
                    delete content_obj;
                    content_obj = new T(a_right);
                    return *this;
                }
            
                My_any(My_any const& a_right)
                  : content_obj(a_right.content_obj ? 
                      a_right.content_obj->clone() : 0)
                {        
                }
            
                std::type_info& type() const {
                    return content_obj ? content_obj->type() : typeid(void);
                }
            };

            現(xiàn)在 my_any 類(lèi)的 content_obj 的類(lèi)型定義成 placeholder * ,在構(gòu)造函數(shù)(和賦值運(yùn)算符)中,我們使用 holder 類(lèi)來(lái)生成真實(shí)的“備份”,由于 holder 是模板類(lèi),它可以根據(jù)賦值的對(duì)象相應(yīng)地保存要我們需要的信息。這樣,我們就完成了在賦值的時(shí)候的“類(lèi)型擦除”啦。在 my_any 的 public 接口( type() )中,利用 placeholder 的虛函數(shù),我們就可以進(jìn)行子類(lèi)提供的那些操作,而子類(lèi),已經(jīng)完整地保存著我們需要的原對(duì)象的信息。

            接著我們看下 boost::function 中的 Type Erasure。相比起 boost::any 來(lái),function 庫(kù)要復(fù)雜得多,因?yàn)檫@里只是想講 boost::function 中的“類(lèi)型擦除”,而不是 boost::function 源碼剖析,所以,我們?nèi)匀槐局?jiǎn)化簡(jiǎn)化再簡(jiǎn)化的目的,只挑著討論一些“必要”的成分。

            我們假設(shè) function 不接受任何參數(shù)。為了更好的說(shuō)明,我先帖代碼,再一步一步解釋?zhuān)⒁猓旅媸且黄谆ɑǖ拇a,幾沒(méi)有注釋?zhuān)f(wàn)別開(kāi)罵,請(qǐng)?zhí)^(guò)這段代碼,后面會(huì)有分段的解釋?zhuān)?/font>

            #include <iostream>
            #include <boost/type_traits/is_pointer.hpp>
            #include <boost/mpl/if.hpp>
            
            using namespace std;
            
            union any_callable {
                void (*fun_prt) (); // 函數(shù)指針
                void * fun_obj;     // 函數(shù)對(duì)象
            };
            
            template<typename Func, typename R>
            struct fun_prt_manager {
                static R invoke(any_callable a_fp) {
                    return reinterpret_cast<Func>(a_fp.fun_prt)();
                }
                static void destroy(any_callable a_fp) {}
            };
            
            template<typename Func, typename R>
            struct fun_obj_manager {
                static R invoke(any_callable a_fo) {
                    return (*reinterpret_cast<Func*>(a_fo.fun_obj))();
                }
                static void destroy(any_callable a_fo) {
                    delete reinterpret_cast<Func*>(a_fo.fun_obj);
                }
            };
            
            struct funtion_ptr_tag {};
            struct funtion_obj_tag {};
            
            template <typename Func>
            struct get_function_tag {
                typedef typename boost::mpl::if_<
                    boost::is_pointer<Func>, // 在 VC10 中標(biāo)準(zhǔn)庫(kù)已經(jīng)有它啦
                    funtion_ptr_tag,
                    funtion_obj_tag
                >::type FunType;
            };
            
            template <typename Signature>
            class My_function;
            
            template <typename R>
            class My_function<R()> {
                R (*invoke)(any_callable);
                void (*destory)(any_callable);
                any_callable fun;
            public:
                ~My_function() {
                    clear();
                }
            
                template <typename Func>
                My_function& operator = (Func a_fun) {
                    typedef typename get_function_tag<Func>::FunType fun_tag;
                    assign(a_fun, fun_tag());
                    return *this;
                }
            
                R operator () () const {
                    return invoke(fun);        
                }
            
                template <typename T>
                void assign (T a_funPtr, funtion_ptr_tag) {
                    clear();
                    invoke = &fun_prt_manager<T, R>::invoke;
                    destory = &fun_prt_manager<T, R>::destroy;
                    fun.fun_prt = reinterpret_cast<void(*)()>(a_funPtr);
                }
            
                template <typename T>
                void assign (T a_funObj, funtion_obj_tag) {
                    clear();
                    invoke = &fun_obj_manager<T, R>::invoke;
                    destory = &fun_obj_manager<T, R>::destroy;
                    fun.fun_obj = reinterpret_cast<void*>(new T(a_funObj));
                }
            
            private:
                void clear() {
                    if (!destory) {
                        destory(fun);
                        destory = 0;
                    }
                }
            };
            
            
            int TestFun() {
                return 0;
            }
            
            class TestFunObj {
            public:
                int operator() () const {
                    return 1;
                }
            };
            
            int main(int argc, char* argv[])
            {
                My_function<int ()> fun;
                fun = &TestFun;
                cout<<fun()<<endl;
                fun = TestFunObj();
                cout<<fun()<<endl;    
            }

            首先需要考慮的是,數(shù)據(jù)成員放什么?因?yàn)槲覀冃枰鎯?chǔ)函數(shù)指針,也需要存儲(chǔ)函數(shù)對(duì)象,所以,這里定義一個(gè)聯(lián)合體:

            union any_callable {
                void (*fun_prt) (); // 函數(shù)指針
                void * fun_obj;     // 函數(shù)對(duì)象
            };

            用來(lái)存放相應(yīng)的“調(diào)用子”。另外兩個(gè)數(shù)據(jù)成員(函數(shù)指針)是為了使用上的方便,用于存儲(chǔ)分別針對(duì)函數(shù)指針和函數(shù)對(duì)象的相應(yīng)的“操作方法”。對(duì)于函數(shù)指針和函數(shù)對(duì)象這兩者,轉(zhuǎn)型(cast)的動(dòng)作都是不一樣的,所以,我們定義了兩個(gè)輔助類(lèi) fun_prt_manager 和 fun_obj_manager,它們分別定義了針對(duì)函數(shù)指針和函數(shù)對(duì)象進(jìn)行類(lèi)型轉(zhuǎn)換,然后再引發(fā)相應(yīng)的“調(diào)用”和“銷(xiāo)毀”的動(dòng)作。

            接下來(lái)是類(lèi)的兩個(gè) assign 函數(shù),它們針對(duì)函數(shù)針指和函數(shù)對(duì)象,分別用不同的方法來(lái)初始化類(lèi)的數(shù)據(jù)成員,你看:

            invoke = &fun_prt_manager<T, R>::invoke;
            destory = &fun_prt_manager<T, R>::destroy;
            fun.fun_prt = reinterpret_cast<void(*)()>(a_funPtr);

            當(dāng) My_function 的對(duì)象是用函數(shù)指針賦值時(shí),invoke 被 fun_prt_manager 的 static 來(lái)初始化,這樣,在“調(diào)用”時(shí)就把數(shù)據(jù)成員轉(zhuǎn)成函數(shù)指針。同理,可以知道函數(shù)對(duì)象時(shí)相應(yīng)的做法(這里就不啰嗦了)。

            但如何確定在進(jìn)行賦值時(shí),哪一個(gè) assign 被調(diào)用呢?我想,熟悉 STL 的你,看到 funtion_ptr_tag 和 funtion_obj_tag 時(shí)就笑了,是的,這里的 get_function_tag 用了 type_traise 的技法,并且,配合了 boost::mpl 提供的靜態(tài) if_ 簡(jiǎn)化了代碼。這樣,我們就完成了賦值運(yùn)算符的編寫(xiě):

                template <typename Func>
                My_function& operator = (Func a_fun) {
                    typedef typename get_function_tag<Func>::FunType fun_tag;
                    assign(a_fun, fun_tag());
                    return *this;
                }

            有了這個(gè)函數(shù),針對(duì)函數(shù)指針和函數(shù)對(duì)象,My_function 的數(shù)據(jù)成員都可以正確的初始化了。

            如我們所見(jiàn),在 My_function 中,使用了很多技巧和輔助類(lèi),以使得 My_funtion 可以獲取在內(nèi)部保存下函數(shù)指針或是函數(shù)對(duì)象,并在需要的時(shí)候,調(diào)用它們。函數(shù)指針或是函數(shù)對(duì)象,一旦賦值給 My_funtion,在外部看來(lái),便失去了原來(lái)的“類(lèi)型”信息,而只剩下一個(gè)共性——可以調(diào)用(callable)

            這兩個(gè)例子已經(jīng)向你大概展示了 C++ 的“類(lèi)型擦除”,最后,再補(bǔ)充一下我的理解:C++中所說(shuō)的“類(lèi)型擦除”不是有“標(biāo)準(zhǔn)實(shí)現(xiàn)”的一種“技術(shù)”(像 CRTP 或是 Trais 技術(shù)那樣有明顯的實(shí)現(xiàn)“規(guī)律”),而更像是從使用者角度而言的一種“行為模式”。比如對(duì)于一個(gè) boost::function 對(duì)象來(lái)說(shuō),你可以用函數(shù)指針和函數(shù)對(duì)象來(lái)對(duì)它賦值,從使用者的角度看起來(lái),就好像在賦值的過(guò)程中,funtion pointer 和 functor 自身的類(lèi)型信息被抹去了一樣,它們都被“剝離成”成了boost::function 對(duì)象的類(lèi)型,只保留了“可以調(diào)用”這么一個(gè)共性,而 boost::any ,則只保留各種類(lèi)型的“type查詢(xún)”和“復(fù)制”能力這兩個(gè)“共性”,其它類(lèi)型信息一概抹掉。這種“類(lèi)型擦除”并不是真正的語(yǔ)言層面擦除的,正如我們已經(jīng)看到的,這一切仍然是在 C++ 的類(lèi)型檢查系統(tǒng)中工作,維持著類(lèi)型安全上的優(yōu)點(diǎn)。

            posted on 2009-12-10 23:05 唐風(fēng) 閱讀(2553) 評(píng)論(9)  編輯 收藏 引用 所屬分類(lèi): 語(yǔ)言技術(shù)

            評(píng)論

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-11 09:00 Touchsoft
            學(xué)習(xí)了……  回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-11 09:14 崇文
            做個(gè)標(biāo)記,等看到這章的時(shí)候再來(lái)看,目前只看到第五章呢。  回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-11 13:21 Vitacy.Tan
            union any_callable {
            void (*fun_prt) (); // 函數(shù)指針
            void * fun_obj; // 函數(shù)對(duì)象
            };
            不用分開(kāi)對(duì)待,直接void * fun就行了.函數(shù)可以直接當(dāng)對(duì)象使用.
            template <typename R,typename F>
            class callable
            {
            public:
            static R call(void * fun){
            return (*static_cast<F *>(fun))();
            }
            static void destory(void *fun){
            delete static_cast<F*>(fun);
            }
            };
            template <typename R>
            class function
            {
            public:
            R operator () (){
            return (*m_call)(m_fun);
            }
            template <typename T>
            void operator=(T fun){
            m_fun = static_cast<void *>(new T(fun));
            m_call=callable<R,T>::call;
            m_destory=callable<R,T>::destory;
            }
            template <typename T>
            R call(){
            (*static_cast<T *>(m_fun))();
            }
            ~function(){
            (*m_destory)(m_fun);
            }
            private:
            void * m_fun;
            R (*m_call)(void *);
            void (*m_destory)(void *);
            };
              回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-12 10:50 唐風(fēng)
            @Vitacy.Tan
            嗯,試過(guò)了你的代碼,確實(shí)在我的例子的情況下,你的做法沒(méi)有問(wèn)題而且更簡(jiǎn)潔。呵,說(shuō)真的,第一次看到 new 一個(gè) function pointer 對(duì)象,有點(diǎn)詫異。后來(lái)想通了,function pointer 也不過(guò)就是一個(gè) pointer 而已。
            但 boost::function 中確實(shí)對(duì)兩者進(jìn)行了區(qū)分對(duì)待,而且考慮了更多的情況情況:
            /**
                   * A buffer used to store small function objects in
                   * boost::function. It is a union containing function pointers,
                   * object pointers, and a structure that resembles a bound
                   * member function pointer.
                   
            */

                  union function_buffer
                  
            {
                    
            // For pointers to function objects
                    mutable void* obj_ptr;

                    
            // For pointers to std::type_info objects
                    struct type_t {
                      
            // (get_functor_type_tag, check_functor_type_tag).
                      const BOOST_FUNCTION_STD_NS::type_info* type;

                      
            // Whether the type is const-qualified.
                      bool const_qualified;
                      
            // Whether the type is volatile-qualified.
                      bool volatile_qualified;
                    }
             type;

                    
            // For function pointers of all kinds
                    mutable void (*func_ptr)();

                    
            // For bound member pointers
                    struct bound_memfunc_ptr_t {
                      
            void (X::*memfunc_ptr)(int);
                      
            void* obj_ptr;
                    }
             bound_memfunc_ptr;

                    
            // For references to function objects. We explicitly keep
                    
            // track of the cv-qualifiers on the object referenced.
                    struct obj_ref_t {
                      mutable 
            void* obj_ptr;
                      
            bool is_const_qualified;
                      
            bool is_volatile_qualified;
                    }
             obj_ref;

                    
            // To relax aliasing constraints
                    mutable char data;
                  }
            ;

            在下淺薄,不能完全明白其中的道理,還請(qǐng)路過(guò)高人指點(diǎn)。
             

             
              回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-13 11:53 唐風(fēng)
            @Vitacy.Tan
            在網(wǎng)上找了一下相關(guān)的資料,發(fā)現(xiàn)這個(gè)問(wèn)題其實(shí)已經(jīng)有了比較多的“討論”,還有專(zhuān)門(mén)論述的文章:
            http://www.safercode.com/blog/2008/11/25/generic-function-pointers-in-c-and-void.html

            簡(jiǎn)而言之,就是:
            不能 void* 和 void(*f)() 合并成一個(gè),原因是對(duì)于 C 標(biāo)準(zhǔn)而言,這兩個(gè)“東西”并不保證一致,函數(shù)指針的大小可能比 void* (也就是指向數(shù)據(jù)的指針大小要大),可能會(huì)包含更多的信息,如果在這之間進(jìn)行轉(zhuǎn)換的話(huà),在某些平臺(tái)會(huì)產(chǎn)生未定義的行為(在 Windows 平臺(tái)下,這樣做是沒(méi)問(wèn)題的,參考http://stackoverflow.com/questions/1867698/casting-a-void-pointer-data-to-a-function-pointer 中的回復(fù))。因此,這么做是為了可移植性的考慮。

            相關(guān)原文如下:
            Why can’t we use void* for a Generic Function Pointer?
            This is because a void* is a pointer to a generic “data” type. A void * is used to denote pointers to objects and in some systems, pointers to functions can be larger than pointers to objects. So, if you convert amongst them, you’ll lose information and hence, the situation would be undefined and implementation dependent. Most compilers won’t even warn you if you convert between them but some might error out, if you try to call such a void * to function pointer converted. But even they might fail to alert you, if you take care of typecasting the call perfectly (Enclose in parentheses before function call brackets). And then, one fine day, you’ll try to compile and run your program on one of the aforementioned systems, and then keep on wondering why your program segfaults.

            Note: C++ does allow this “conditionally” which means that such a conversion is allowed but a compiler is not bound to implement this feature, which again makes its usage circumspect.

            另外,我還是不太明白,function pointer 可能攜帶的其它信息是什么,呵呵,再查查嘍。

            謝謝 Vitacy.Tan 的回復(fù),讓我能更深入的了解這方面的知識(shí)。
            嗯,有人能參與討論就是好啊,希望大家多指點(diǎn)。



              回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-13 12:05 唐風(fēng)
            @Vitacy.Tan
            話(huà)又說(shuō)回來(lái),在你的做法中,并沒(méi)有直接在 function pointer 和 void* 之間進(jìn)行轉(zhuǎn)型,而是為 function pointer 創(chuàng)建(new)了一個(gè)對(duì)象,賦給 void*,這樣做我感覺(jué)是沒(méi)有問(wèn)題的,這時(shí)候 void* 指向的仍然是一個(gè)“對(duì)象”,呵呵。
            但這么做可能在“效率”上不如直接備份 function pointer 。畢竟,創(chuàng)建時(shí)候的 new 和調(diào)用時(shí)的轉(zhuǎn)型加最后的 delete,都比直接存 function pointer 負(fù)擔(dān)大。但這樣做獲得了代碼上的一致性,我倒是挺喜歡的,呵呵(如果確實(shí)沒(méi)有“我所不知道的問(wèn)題的話(huà)”)。
              回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-14 11:16 Vitacy.Tan
            function pointer 可能攜帶的其它信息是什么
            參數(shù)個(gè)數(shù) 類(lèi)型 還有像int a(int b=1);
            在C++里參數(shù)個(gè)數(shù) 類(lèi)型在函數(shù)名里(指針好像也沒(méi)這個(gè)),默認(rèn)參數(shù)可以重載解決
              回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-17 10:45 U2U
            很感謝你這篇文章,寫(xiě)得很好!  回復(fù)  更多評(píng)論
              

            # re: C++中的類(lèi)型擦除(type erasure in c++) 2009-12-18 07:38 欲三更
            恩,上面那個(gè)回復(fù)里用“指針的指針”規(guī)避對(duì)象指針和函數(shù)指針的大小不一樣這一點(diǎn),挺好的。  回復(fù)  更多評(píng)論
              

            久久久青草青青国产亚洲免观| 欧美精品福利视频一区二区三区久久久精品| 91久久精品国产免费直播| 久久久久久免费视频| 亚洲国产精品婷婷久久| 亚洲综合日韩久久成人AV| 久久久久亚洲AV无码去区首| 久久精品夜夜夜夜夜久久| 欧美精品丝袜久久久中文字幕| 国产成人精品久久免费动漫| 久久天天躁狠狠躁夜夜avapp | 日韩人妻无码一区二区三区久久99| 国产精品久久久久aaaa| 亚洲AV日韩AV天堂久久| 人妻系列无码专区久久五月天| 青青青伊人色综合久久| 99久久精品费精品国产一区二区| 影音先锋女人AV鲁色资源网久久 | 久久99精品综合国产首页| 无码人妻少妇久久中文字幕蜜桃 | 国产欧美久久久精品影院| 国产免费久久久久久无码| 国产精品久久一区二区三区| 久久综合噜噜激激的五月天| 久久亚洲sm情趣捆绑调教| 精品久久久久久久久免费影院| 久久久久九九精品影院| 国产叼嘿久久精品久久| 欧美综合天天夜夜久久| 免费观看成人久久网免费观看| 国产精品视频久久久| 99国产欧美久久久精品蜜芽| 国产精品一久久香蕉国产线看| 久久精品无码专区免费青青| 99久久99久久久精品齐齐| 99久久精品国内| 99久久久久| 久久久久这里只有精品| 午夜精品久久久久久影视777| 性高朝久久久久久久久久| 久久91精品国产91久|