2011-05-09 48 views
1

我目前正在使用一個枚舉映射到一個Base *數組。每個派生類型由枚舉給出一個索引。異構指針容器

enum DerivedType { 
    DERIVED_TYPE_1 = 0, 
    DERIVED_TYPE_2, 
    ... 
    NUM_DERIVED_TYPES 
}; 


class Base { 

}; 


class Derived1 : public Base { 
    static const DerivedType type; 
}; 
const DerivedType Derived1::type = DERIVED_TYPE_1; 


class Derived2 : public Base { 
    static const DerivedType type; 
}; 
const DerivedType Derived2::type = DERIVED_TYPE_2; 


class Container { 
    Base* obs[NUM_DERIVED_TYPES]; 

    template<class T> 
    void addOb(T* ob) { 
     obs[T::type] = ob; 
    } 

    template<class T> 
    T* getOb() { 
     return (T*) obs[T::type]; 
    } 

    Base* getOb(DerivedType type) { 
     return obs[type]; 
    } 
}; 

由於每個派生類型的索引是在編譯時已知的,是有辦法具有非模板getOb(DerivedType type)返回正確DerivedN指針,可能通過在一個int仰視類型名稱 - >類型名稱地圖?或者有更好的方法來實現這種類型的模式?此外,將每個Derived類型添加到任何數據結構將其指定爲其索引值是很好的。基本上,我需要一個靜態異構指針容器,它可以通過類型或索引來訪問,同時返回正確的派生*。我猜測Boost有些東西可行,但我還沒有找到它。

感謝您的任何幫助。

回答

2

雖然我不是很會怎樣看100%確信我正確理解了這個問題, 可能是你提到的(或類似的) 與boost::fusionboost::mpl
例如:

#include <boost/fusion/include/map.hpp> 
#include <boost/fusion/include/at_key.hpp> 
#include <boost/mpl/vector.hpp> 
namespace bf = boost::fusion; 
namespace bm = boost::mpl; 

// This order has to match with the enumerators in DerivedType 
typedef bm::vector< Derived1, Derived2 > DerivedTypes; 

typedef bf::map< bf::pair< Derived1, Derived1* > 
       , bf::pair< Derived2, Derived2* > > Container; 

int main() { 
    Container c(bf::make_pair< Derived1, Derived1* >(0) 
       , bf::make_pair< Derived2, Derived2* >(0)); 
    Derived1 d1; 
    Derived2 d2; 
    bf::at_key<Derived1>(c) = &d1; // access with type 
    bf::at_key<Derived2>(c) = &d2; 
    // access with enum 
    bf::at_key< bm::at_c< DerivedTypes, DERIVED_TYPE_1 >::type >(c) = &d1; 
    bf::at_key< bm::at_c< DerivedTypes, DERIVED_TYPE_2 >::type >(c) = &d2; 
} 
+0

非常好,正是我在找的,謝謝。我做的一個改進是讓map自動從vector中填充:'typedef bm :: fold ,bm :: push_back >>::: type Container;' – Ryan 2011-05-15 02:54:29

+0

謝謝,很高興幫助:-) – 2011-05-15 07:56:05

0

(1)is there a way to have the "non-template" getOb(DerivedType type) return the correct DerivedN pointer

不幸的是不可能的。對於非模板函數,返回類型只能是單一類型,並且在您的情況下必須是Base*類型。當前實施Base* getOb(DerivedType type);是正確的。

(2)is there a better way to implement this type of pattern?

至少你可以通過使用模板化的中級班(沒有任何開銷),這將初始化DerivedType變量爲你減輕你的工作。例如,聲明類似如下:

template<DerivedType TYPE> 
struct Link : Base { 
    static const DerivedType type; 
}; 
template<DerivedType TYPE> 
const DerivedType Link<TYPE>::type = TYPE; 

現在Link<DerivedType>應繼承的派生類,如:

class Derived1 : public Link<DERIVED_TYPE_1> { 
// no need to declare/define an explicit variable for DerivedType now. 
}; 
0

那麼,你現在有看起來很堅實的給我。我看到的唯一問題是,在運行時只有Base*可用,因爲單個函數只能返回1個類型。要允許多種類型的回報,而無需指定一個額外的參數,你可以假一功能,像這樣:

// if employed as a free function 
class getOb{ 
    DerivedType _type; 
public: 
    getOb(DerivedType type) 
    : _type(type) {} 

    template<class T> 
    operator T*() const{ 
    Base* ptr; 
    // fetch correct pointer from wherever 
    // using _type, if non-existant use 0 
    return (T*) ptr; 
    } 
}; 

使用像

Derived1* pd = getOb(DERIVED_TYPE_1); 
assert(pd != 0); 

的參數傳入構造,而實際的功能身體在於轉換操作符。當然,這只是看起來不錯,作爲一個獨立的功能,所以在這裏,如果你想實現它作爲一個成員函數

class GetObClass{ 
    mutable DerivedType _type; 
public: 
    GetObClass& operator()(DerivedType type) const{ 
    _type = type; 
    return *this; 
    } 

    // template conversion operator as before 
}; 

使用像

class Container{ 
public: 
    const GetObClass getOb; 
}; 

Container c; 
Derived1* pd = c.getOb(DERIVED_TYPE_1); 
assert(pd != 0);