异构指针容器

时间:2011-05-09 03:05:03

标签: c++ templates

我目前正在使用枚举映射到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中的typename - &gt; typename地图?或者有更好的方法来实现这种类型的模式?此外,让每个Derived类型将其自身添加到任何数据结构中,为其指定索引值将是很好的。

基本上,我需要一个静态异构指针容器,可以按类型或索引访问,同时返回正确的Derived *。我猜Boost有一些可行的方法,但我还没有找到它。

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

虽然我并非百分之百地确信我正确理解了这个问题, 可能你所提到的(或类似的)可以实现 使用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;
}

答案 1 :(得分: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;

现在应该为Derived类继承Link<DerivedType>,例如:

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

答案 2 :(得分: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);