我目前正在使用枚举映射到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有一些可行的方法,但我还没有找到它。
感谢您的帮助。
答案 0 :(得分:2)
虽然我并非百分之百地确信我正确理解了这个问题,
可能你所提到的(或类似的)可以实现
使用boost::fusion
和boost::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);