模板允许在c ++中自动创建许多具有相同接口的类,但存储的数据不同。
我正在寻找类似的东西(我不知道它是否存在,这就是我在这里问的原因),它会自动为我创建一个只存储数据库子集的对象变体。
让我说我有一个
class FullClass
{
public:
bool A;
int B;
float C;
double D;
};
然后我想拥有这些字段的所有可能组合,例如:
class BDClass
{
public:
int B;
double D;
};
或
class BCDClass
{
public:
int B;
float C;
double D;
};
我希望能够从任何变体类转换为FullClass,以便复制定义的字段,并将缺少的字段设置为defaultvalues:
FullClass foo;
BDClass bar = BDClass(3, 5.0);
foo = (FullClass) bar;
是否有任何机制让编译器为我创建这些变体,或者我是否必须自己定义所有可能的组合?
谢谢!
编辑:
为什么我要找这个?
我有一个遵循策略模式的软件构造。因此,我有一堆使用相同界面的不同算法(超过30个)。客户端应该能够使用此接口,而无需知道当前正在运行的确切算法。客户端计算这样的'FullClass'对象并将其传递通过接口 - 但是,每个算法仅使用此对象中提供的字段的子集(并且每个算法使用不同的算法)。 这种策略模式构造是固定的,我不能改变它。
现在我想'记录'这种生成的'FullClass'对象的序列,这样就可以重复使用这个构造的完整流程,而不必重新计算那些'FullClass'对象。然而,这是很多数据(出于性能原因我想保留在内存中)并且由于大多数算法只使用一小部分字段,我只想存储有效使用的字段
答案 0 :(得分:1)
我甚至无法想象你为什么需要这个,但你可以尝试使用mixins:
class Dummy
{
};
<template Base>
class AClass : public Base
{
public:
bool A;
};
<template Base>
class BClass : public Base
{
public:
int B;
};
... //( etc)
BClass< AClass<Dummy>> abClass;
abClass.B = 4;
abClass.A = false;
如果你继续前进,你将能够做到:
DClass< CCLass< BClass< AClass<Dummy>>>> abcdClass;
答案 1 :(得分:1)
我可能错了,或者它可能是您的问题的无效解决方案,但也许使用元组将解决它:http://www.boost.org/doc/libs/1_41_0/libs/tuple/doc/tuple_users_guide.html
那就是说,你应该解释你想要解决的问题,正如尼尔所说。你为什么需要这个。
答案 2 :(得分:0)
首先,您可以为每种数据类型定义四个类,然后为类型对声明模板类,然后为三种类型组合声明模板类,然后为四种类型组合。你不能比这更简单。
答案 3 :(得分:0)
我认为您可以使用私有类数据模式执行某些操作,然后使用一些可怕的memcopy技巧:
class Full
{
private:
struct fullData
{
a;
b;
c;
d;
e;
...
z;
} * m_pData;
public:
Stuff!
}
class Partial
{
private:
struct partialData
{
a;
b;
c_filler; //This is an issue
d;
}
public:
Different Stuff!;
}
然后,当你复制时,只需将partialData的内存直接复制到fullData中,用零填充其余的fullData。
问题是这只适用于不需要你使用它们的构造函数的数据类型(因此,这里没有安全检查),你必须填写填充(如上所述)以确保你的数据行正确的。
但是你的拷贝构造函数变成了一个memcopy,然后是一个memfill; (注意,我几乎肯定有memcopy和填充语法错误)
template<class T>
Full(T& t)
{
m_pData = new fullData;
memcopy(/*to*/m_pData, /*from*/Partial->getData(), /*how much to copy*/ sizeof(T));
memfill(/*tp*/m_pData, /*how much to copy*/ sizeof(fullData) - sizeof(T), /*with*/ 0);
}
可能适合您的特定情况,但不是特别安全或漂亮。
答案 4 :(得分:0)
您是否考虑过只为codegen编写预处理器,您需要什么?
答案 5 :(得分:0)
我个人非常欣赏Boost.Fusion;)
在这里,我会使用boost::fusion::map
,因为它可以很容易地混合类型。
您需要使用标记类型(仅用于编译目的的类型)和用于存储数据的实际类型的组合。
让我们定义我们的标签:
class a_tag { typedef bool type; };
class b_tag { typedef int type; };
class c_tag { typedef float type; };
class d_tag { typedef double type; };
然后你可以使用Boost.Preprocessor编写一个宏,它获取标签列表并生成相应的boost::fusion::map
GENERATE_MY_TYPE(TypeName, (a_tag)(b_tag)(c_tag)(d_tag));
// For information: (a_tag)(b_tag)(c_tag)(d_tag) is called a sequence in PP
类型应为:
typedef boost::fusion::map<
std::pair<a_tag, a_tag::type>,
std::pair<b_tag, b_tag::type>,
std::pair<c_tag, c_tag::type>,
std::pair<d_tag, d_tag::type>
> TypeName;
或者更可能是使用boost :: fusion :: map作为实现细节的包装器,例如:
// defined once
template <class Vector>
struct TemplateType
{
typedef Vector tags_type;
typedef detail::deduce<Vector>::type data_type
// which for Vector = boost::mpl::vector<a_tag, b_tag, c_tag, d_tag> should be
// typedef boost::fusion::map<
// std::pair<a_tag, a_tag::type>,
// std::pair<b_tag, b_tag::type>,
// std::pair<c_tag, c_tag::type>,
// std::pair<d_tag, d_tag::type>
// > data_type;
data_type m_data;
template <class T>
boost::fusion::result_of::at<T, data_type> at()
{
return boost::fusion::at<T>(m_data);
}
};
// Generated by the macro, filling boost::mpl::vector by iteration
// the sequence
typedef TemplateType< boost::mpl::vector<a_tag, b_tag, c_tag, d_tag> > TypeName;
然后您只需要定义的类型来提供标记子集的转换技巧。如果您只需要完整的子集,则可能只定义一次。
template <class Vector>
TypeName toTypeName(TemplateType<Vector> const& arg)
{
TypeName result;
result.fill(arg);
return result;
}
将填充定义为:
namespace detail
{
class NoAssign
{
template <class Pair, class TT> static Do(Pair const&, TTconst&) { }
};
class Assign
{
template <class Pair, class TT>
static Do(Pair& p, TTconst& tt)
{
p.second = tt.at<typename Pair::first_type>();
};
};
template <class Vector>
class Filler
{
public:
Filler(TemplateType<Vector> const& ref): m_ref(ref) {}
template <class T, class U>
void operator()(std::pair<T,U>& p) const
{
typedef typename boost::mpl::find<T,Vector>::type it;
typedef typename boost::mpl::end<Vector>::type end;
typedef typename boost::mpl::if< boost::same_type<it,end>, NoAssign, Assign> assign;
assign::Do(p, m_ref);
}
private:
TemplateType<Vector> const& m_ref;
};
}
template <class Vector>
template <class OV>
void TemplateType<Vector>::fill<OV>(TemplateType<OV> const& rhs)
{
boost::fusion::for_each(m_data, detail::Filler<OV>(rhs));
}
我喜欢这些问题,但当然被迫使用Meta Template Progamming和Preprocessing来生成一些模板类/方法...意味着一些冗长的解决方案和一些令人头疼的问题。一旦完成,语法可以非常整洁(对于用户而言)。