views:

208

answers:

6

hi!

templates allow in c++ to automatically create a lot of classes with the same interface, but different data stored.

i'm looking for something similar (i don't know whether it exists, that's why I ask here) that automatically creates for me variations of an object storing only a subset of the datamembers.

let's say i have a

class FullClass
{
public:
    bool A;
    int B;
    float C;
    double D;
};

then i would like to have all possible combinations of those fields like for example:

class BDClass
{
public:
    int B;
    double D;
};

or

class BCDClass
{
public:
    int B;
    float C;
    double D;
};

and i want to be able to cast from any of the variation classes to FullClass such that the defined fields will be copied, and the missing fields are set to defaultvalues:

FullClass foo;
BDClass bar = BDClass(3, 5.0);
foo = (FullClass) bar;

Is there any mechanism that let's the compiler create those variations for me, or do I have to define all possible combinations myself?

thanks!

edit:

why am I looking for this?

I have a software construct that follows the strategy pattern. thus, i have a bunch of different algorithms (more than 30) using the same interface. the client shall be able to use this interface without knowing what exact algorithm currently is running behind. the client calculates such a 'FullClass' object and passes it through the interface - however, each algorithm uses only a subset of the fields provided in this object (and each algorithm uses different ones). This strategy-pattern construct is fixed and i cannot change it.

Now i want to 'record' the sequence of such generated 'FullClass' objects, such that the complete flow of the usage of this construct can be repeated without having to recalculate those 'FullClass' objects. However, this is a lot of data (which i'd like to keep in mainmemory for performance reasons) and since most of the algorithms only use a small subset of the fields, i only want to store the fields which are effectively used

+1  A: 

I cannot even imagine why do you need this, but you can try use 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;

And if you will keep going you will be able to do:

DClass< CCLass< BClass< AClass<Dummy>>>> abcdClass;
Artem Barger
this looks neat! i'll try that!
genesys
will it also be possible to convert a variable from for example abClass to abcdClass?
genesys
My first intention was to say no, but actually need to be verified, since it make a sense that it should be possible. Let say you should be able to assign abcdClass to abClass.
Artem Barger
You may also be unable to convert between an adClass and a bcClass, since they don't share an inheritance but dummy.You may also be unable to convert between an abClass and a badcClass, because the inheritance order is different. That said, using typedefs to have everything setup nicely, and then using only the typedefs and not the templates themselves, may resolve some of these issues.
Narfanator
Now this looks like a hand made typelist. Why?Check out Loki for meta-programming hacks.@Artem: What you're doing looks like GenScatterHierarchy<TList>.Check Modern C++ Design by Andrie Alexandrescu.
the_drow
@Narfanator: Yes, you right I'm aware of those problems, I've only tried to give some direction and not full solution.
Artem Barger
A: 

First, you can define four classes for each data type, then declare templae class for type pairs, then for three-type combinations, then for four ones. You can't get it any simpler than that.

alemjerus
It fails to meet the conversion criteria.
Matthieu M.
+1  A: 

I might be wrong or it might be an non-efficient solution to your problem, but maybe using tuple will solve it : http://www.boost.org/doc/libs/1_41_0/libs/tuple/doc/tuple_users_guide.html

That said, you should explain the problem you're trying to solve, as Neil said. Why would you need this.

Klaim
A: 

I think you could do something using the private class data pattern, and then some terrible memcopy tricks:

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!;
}

Then, when you copy, just literally copy the memory of partialData into fullData, filling the rest of fullData with zeros.

The issues are that this only works with datatypes that don't need you to use their constructors (so, there's no safety checks in here), and you have to put in padding (as above) to make sure your data lines up properly.

But your copy-constructor gets to be a memcopy then a memfill; (note, I almost certainly have the memcopy and fill syntax wrong)

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);
}

May work for your particular situation, but it's not particularly safe or pretty.

Narfanator
A: 

Have you considered just writing a preprocessor to codegen what you need?

jeffamaphone
i think i'd need some kind of for-loop to create this in a preprocessor - is there a preprocessor directive to do a loop?
genesys
No, I mean write your own program that does the code gen. Perhaps use of the word preprocessor was incorrect.
jeffamaphone
A: 

I personally really appreciate Boost.Fusion ;)

Here, I would use boost::fusion::map since it allows to mix types quite easily.

You need to use a combination of tags types (types only used for compilation purpose) and of real types, used to store data.

Let's define our tags:

class a_tag { typedef bool type; };
class b_tag { typedef int type; };
class c_tag { typedef float type; };
class d_tag { typedef double type; };

Then you can write a macro using Boost.Preprocessor which takes the list of tags and generates the appropriate 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

The type shall be something like:

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;

Or more likely a wrapper using the boost::fusion::map as an implementation detail, say:

// 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;

And then you only need the type defined to provide a conversion trick from a subset of tags. This might be defined only once if you need only have the full subset.

template <class Vector>
TypeName toTypeName(TemplateType<Vector> const& arg)
{
  TypeName result;
  result.fill(arg);
  return result;
}

With fill being defined as:

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));
}

I love those problems, but of course being forced to use both Meta Template Progamming AND Preprocessing to generate some template classes / methods... means some lengthy solutions and some headaches. Once done however the syntax can be really neat (for the user).

Matthieu M.
that looks fancy - i don't get everything - but i don't think this yelsds nice POD structs storing only the membervalues i need, does it?
genesys
Whether they are POD or not is a matter of implementation, I don't know exactly how Fusion is implemented behind the covers. A quick test tends to prove that the `fusion::map` is twice as big as the corresponding struct.
Matthieu M.