C ++使用不同的字段组合创建类的变体

时间:2010-01-03 15:29:18

标签: c++ templates field

模板允许在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'对象。然而,这是很多数据(出于性能原因我想保留在内存中)并且由于大多数算法只使​​用一小部分字段,我只想存储有效使用的字段

6 个答案:

答案 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来生成一些模板类/方法...意味着一些冗长的解决方案和一些令人头疼的问题。一旦完成,语法可以非常整洁(对于用户而言)。