Related
After I learned how to pass static function (HashFunction) as a class (Collection<T,HashFunction>) template parameter, I am very addicted to it.
I use it in many places ... now I just realize that if I want to change HashFunction's signature, I will be obliged to modify code in various location.
Example
There are some classes (B and C) that are designed to be used as element of a custom collection (Collection<T,HashFunction>):-
class B{
int bHash;
public: static int& getHash(B& b){return b.bHash;} //#1
//.... other complex thing about B ....
};
class C{
int cHash1;
public: static int& getHash1(C& c){return c.cHash1;} //#2
int cHash2;
public: static int& getHash2(C& c){return c.cHash2;} //#3
//.... other complex thing about C ....
};
//There are about 20 places, i.e. #1 to #20
//They have a thing in common : return an integer field
The Collection<T,HashFunction> (its code is not shown) works similar as a hashset of T.
Here is the usage:-
Collection<B,&B::getHash> collectB;
Collection<C,&C::getHash1> collectC1;
Collection<C,&C::getHash2> collectC2;
//There are about 30+ locations.
Problem
Signature of the hash function (#1,#2,#3 and inside Collection) may require change in the future.
For example, the signature may change from
int bHash;
static int& getHash(B& b){return b.bHash;}
to
HashStructure bHash; //"HashStructure" is a new class
static HashStructure& getHash(B& b,int notUsed){return b.bHash;}
//They tend to still have a thing in common : return a "HashStructure" field
//Here is the maximum possible difference :-
HashStructure bHash[3];
static HashStructure& getHash(B& b,int index){return b.bHash[index];}
//They are likely consistent for both B and C.
Changing Collection to use the new signature is not hard, but changing all signature of #1 to #20 is tedious.
This indicates a maintainability problem.
Question
Suppose I can reverse time to when there are only #1 to #3,
how to modify the code/design (in the example) to prevent maintainability problem.
Opinions:
I should use inheritance (A and B derived from a new class),
but it doesn't fit. (Because B can have unlimited amount of hash function. Moreover, the names of hash function are likely different from A's.)
Some certain design pattern might help. (?)
Variadic template and SFINAE might help. (from Danh's comment, thank!)
To prevent the maintainability problem, I would not have used functions as template arguments in the first place. I would have gone for a 1 type == 1 hash function design, similar to what the STL does to solve the same problem.
Whichever reason you have to stick the different hash functions into the same class can be solved using either inheritance or friendship.
This way, only the call sites have to be updated when the signature change. You could also provide both signatures until every call site has been updated, allowing you to update the code base step by step.
Example:
#include <utility>
class C {
static int cHash1;
};
int C::cHash1 = 0;
struct C1 : public C {
static int hash(C &value);
static int hash(C &value,bool);
};
struct C2 : public C {
static int hash(C &value);
static int hash(C &value,bool);
};
template <class Value, class HashFunction>
struct Collection {
using key_type = decltype(HashFunction::hash(std::declval<HashFunction&>()));
};
template <class Value, class HashFunction>
struct CollectionUpdated {
using key_type = decltype(HashFunction::hash(std::declval<HashFunction&>(), std::declval<bool>()));
};
int main() {
Collection<int, C1> c1;
Collection<int, C2> c2;
CollectionUpdated<int, C1> c1_up;
CollectionUpdated<int, C2> c2_up;
return 0;
}
It seems that getHash can be factorized into
template <typename T, int (T::*hash)>
int& getHash(T& t) { return t.*hash; }
Then usage is:
Collection<B, &getHash<B, &B::bHash>> collectB;
Collection<C, &getHash<C, &C::cHash1>> collectC1;
Collection<C, &getHash<C, &C::cHash2>> collectC2;
And later, you can change implementation of getHash once:
template <typename T, int (T::*hash)[3]>
static HashStructure& getHash(T& t, int index) { return (t.*hash)[index]; }
I have a class defined like this
class A
{
private:
map<int,vector<int>> m;
public:
vector<int> GetJsonVal(int k)
{
return m[k];
}
};
I would like to change it into something like this
template<class T>
class A
{
private:
map<int,T> m;
public:
T GetJsonVal(int k)
{
return m[k];
}
};
However, I have many other places that plainly use only type A, so if I change my class into the latter, I have to fix a lot i.e change all into A<type>, which I don't want. In those places I simply do void func(A*p) or A& r=....
So, how can I both use i.e A<float> and A anywhere I like ?
So, the easiest and most legible solution that comes to mind is a type alias:
template <typename T>
class Tool {
private:
map<int,vector<T>> m;
public:
vector<T> GetJsonVal(int k) {
return m[k];
}
};
using A = Tool<int>;
And so now the old code can continue using A, and all new code can use Tool<int> or another type alias.
You could use type-erasue, but will still need to update the code here and there... An approach could be doing something like:
class A {
map<int, boost::any> m;
template <typename T>
T valueAs(int idx);
};
A a;
a.valueAs<int>();
You would have the implementation verify that the type stored and the type retrieved are the same. Then you would probably want to go to all existing uses of A and enforce the check (or check the potential error).
That is, if you want to support mixed types inside A... if you each A can only hold a particular type, you can just make a ATmpl type with the contents in the question, and then typedef ATmpl<vector<int>> A;. At this point you would still have to fix some use cases (specifically: forward declarations)...
Use template class specialization, I would say
template <> class A<vector<int>>
{
// all your old code here
}
should work...
UPDATE
Just to be clear, there is a semantic difference between template specialization and type alias. With template specialization you could put your (true and tested and bug-for-bug compatible) code into specialization and use new and shiny (but potentially buggy code) elsewhere in new production, and later when you fill it is good enough you could remove specialization and use only new code. With type specialization it is new code everywhere right away...
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have a lot of subclasses of an abstract class Letter, like A, B, C, D, etc. Letter has an integer ID variable, and every subclass of Letter gets assigned a unique id.
I then have another class, call it Alphabet. Alphabet has an
list<shared_ptr<Letter>>
member. Here is the problem... I would like to elegantly add B's and C's or other subclasses of Letter to particular instances of Alphabets. I think the most convenient way to do this would be to use the integer id of subclass somehow. In other words, I want to be able to have something like Alphabet.addLetter(int id), so if I did alphabet1.add(14), it would somehow add a shared_ptr for class H to the list.
Is there an elegant way to do this, avoiding some huge if statement where that I need to constantly update every time I add or remove one of the B, C, D, E, etc. classes? I'm hoping there's some kind of template-solution, but I'm not very familiar with advanced c++ notions like factories and templates. The naive thing I wanted was some kind of vector/map that converted my ids into class names, so that I could do something like
list.push_back(shared_ptr<classVector(i)>(new classVector(i))
or something like that, though I have no idea if that's possible.
Thanks!
p.s. I just chose the Alphabet example because I didn't want to give unnecessary detail. Obviously I'm not trying to design alphabets in such a silly way, lol.
edit: I'm struggling to make this make sense. My goal is to be able to create new subclasses of Letter very quickly with minimal effort. I would like to avoid having to type out code that looks like...
list.push_back(shared_ptr<X>(...));
every time I make a new letter. Does this make sense at all?
This is pretty hard to follow, but I think what you want is something along the lines of the following:
// where make_unique<> is from C++14 in std:: or like:
template <typename T, typename ... TArgs>
std::unique_ptr<T> make_unique(TArgs &&... args) {
return std::unique_ptr<T>(new T(std::forward<TArgs>(args)...));
}
struct Letter {
virtual ~Letter() { }
virtual void foo() = 0;
};
template <unsigned int N> struct LetterCode; // Note: no default implementation!
struct Alphabet {
// Indexed access, if you'll have 1 of each type max:
std::vector<std::unique_ptr<Letter>> v;
// If you don't need parameters, as mentioned in comments below ...
template <unsigned int N>
void addLetterN() {
if (N > v.size() + 1) { v.resize(N + 1); }
v[N] = make_unique<LetterCode<N>::type>(); // see below ...
}
// If your coding is complete from 0...N, this does the whole shebang.
template <unsigned int N>
void addLettersN() {
addLetters<N - 1>();
addLetterN<N>();
}
template <>
addLettersN<0>() {
addLetterN<0>();
}
};
If you need numeric codes for something like deserialization and never need constructor arguments, you can use a type trait template like follows to statically 'register' the types:
struct B : Letter {
B(int n, bool b, char const *name);
void foo() override;
};
template <> struct LetterCode<2> { using type = B; };
struct C : Letter {
C(double d);
void foo() override;
};
template <> struct LetterCode<3> { using type = C; };
void bar() {
Alphabet a;
a.addLetterN<2>();
a.addLetterN<3>();
// --OR--
a.addLettersN<3>(); // will do 0...3 in one fell swoop.
for (auto &i : a.v) {
if (!i) { continue; } // v is sparse, unlike l
i->foo();
}
If you need generalized constructor argument passing, you can use perfect forwarding, which is designed for cases like this and obviates the need for enum IDs, etc., from older styles of factories:
struct Alphabet {
std::list<std::unique_ptr<Letter>> l;
// variadic factory that chucks new (shared_ptr) objects in the list.
template <typename T, typename ... TArgs>
void addLetter(TArgs && ... args) {
l.push_back(make_unique<T>(std::forward<TArgs>(args)...));
}
};
void baz() {
Alphabet a;
a.addLetter<B>(1, false, "pony");
a.addLetter<C>(2.718281828);
for (auto &i : a.l) {
i->foo(); // can call virtual funcs here all you want ...
}
}
This is relatively easy if I understood you correctly, using what's called a factory-pattern.
If you can list all of the derived types:
Letter header:
struct Letter {
enum LetterEnum {LetterA, LetterB, LetterC, LetterCount};
virtual ~Letter() {} //base types should always have virtual destructor
virtual void foo() = 0;
static std::unique_ptr<Letter> construct(LetterEnum c);
};
Implementation headers:
struct A : Letter {
void foo() override;
};
struct B : Letter {
void foo() override;
};
struct C : Letter {
void foo() override;
};
Letter body:
std::unique_ptr<Letter> Letter::construct(Letter::LetterEnum c)
{
switch(c) {
case Letter::LetterA : return make_unique<A>();
case Letter::LetterB : return make_unique<B>();
case Letter::LetterC : return make_unique<C>();
default: throw ...;
}
}
Usage:
int main() {
char c;
std::cin >> c;
//get a letter of the derived type associated with the letter entered
std::unique_ptr<Letter> ptr = Letter::construct(c);
}
If you can't list all of the derived types:
Allow the derived types to register themselves with the Letter class, and then Letter can use that to create each of the derived types. This way, adding and deleting the derived types involves no changes to any other files. Easy!
struct Letter {
virtual ~Letter() {} //destructor is always virtual when inheretence is involved
....
//this is a "shared" function in the Letter class itself
//it takes a letter, and returns a dynamically allocated instance
//of the derived type corresponding with that letter
static std::unique_ptr<Letter> construct(char c);
//this typedef represents the actual function that returns
//each dynamically allocated derived type
typedef std::function<std::unique_ptr<Letter>()> letter_ctor;
//this is a "shared" function in the Letter class itself
//it takes a letter, and a function that creates derived types,
//and saves them inside the container ctors
static bool register(char c, letter_ctor func);
private:
//this is a "shared" member in the Letter class.
//There is only one shared by all of the Letters. Like a global.
//When you give it a letter, it gives you a function.
//and is VERY fast for large numbers of entries
static std::unordered_set<char,letter_ctor> ctors;
};
and in your implementation file:
//here's the function that derived types register themselves with
//pretty straightforward, just inserts the pair into the unordered_map
bool Letter::register(char c, Letter::letter_ctor func)
{return Letter::ctors.insert(std::make_pair(c,std::move(func))).second;}
//and here's the function that creates the derived types
//it checks if the letter is in the unordered_map
//if the letter isn't there, it throws an exception
//otherwise, it calls the function associated with that letter
//which creates the derived type on the heap, and returns a pointer to it
std::unique_ptr<Letter> Letter::construct(char c)
{
auto it = Letter::ctors.find(c);
if (it == Letter::ctors.end())
throw ...;
return it->second(); //construct that letter
}
and then your derived types do this:
//you know this part
struct LetterA : public Letter
{
....
};
//derived types have to register themselves:
//this is a global, so when the program loads, it automatically calls this
//even before main runs*
//it registers the letter 'A' and a function that creates a LetterA class on the heap
static bool registerA = Letter::register('A', [](){return make_unique<LetterA>();});
and then you can easily create arbirary derived types!
int main() {
char c;
std::cin >> c;
//get a letter of the derived type associated with the letter entered
std::unique_ptr<Letter> ptr = Letter::construct(c);
}
*It doesn't always get called before main. If you have problems, put an bool init_A(); in the A header, and bool init_A(){return true;} in the A implementation file, and in your main file have static bool AInit=init_A(); which should force it. This is almost never needed in practice though.
As a side note, these depend on having a make_unique, which should have been in C++11, but was left out due to oversight. It will be in C++14. In the meantime, use this:
template<class T, class...Us>
std::unique_ptr<T> make_unique(Us&&...us)
{return std::unique_ptr<T>(new T(std::forward<Us>(us)...));}
My understanding is that you want to create a instance of one of the classes, dependend on an id which relates to the class from which an instance should be created.
If so, please have a look for factory pattern. There are a lot of factory implementations, also based on template recursive expansion of a typelist.
Pseudo Code:
Factory<A,B,C,D> fac; // the list must be changed, if some more classes comes and goes
id_type id;
list<base> l;
l.push_back=fac.Create(id);
It is also quite simple to implement such a class yourself.
The goal is simple: create the function factories that returns an array of Alphabet makers.
The index of the letter and the index into the array will be the same.
Ideally, we want to auto-generate said index without having to manually set it.
#include <memory>
#include <vector>
#include <iostream>
template<class T>using Type=T;
template<class...Ts>struct types:std::integral_constant<unsigned,sizeof...(Ts)>
{typedef types type;};
template<class T,class types>struct index_of;
template<class T,class T0, class...Ts>struct index_of<T,types<T0,Ts...>>:
std::integral_constant<unsigned,index_of<T,types<Ts...>>::value+1>
{};
template<class T,class...Ts>struct index_of<T,types<T,Ts...>>:
std::integral_constant<unsigned,0>
{};
template<unsigned,class types>struct type_at;
template<unsigned N, class T,class...Ts>struct type_at<N,types<T,Ts...>>:
type_at<N-1,types<Ts...>> {};
template<class T,class...Ts>struct type_at<0,types<T,Ts...>>{
typedef T type;
};
template<unsigned N,class types>
using type_at_t=typename type_at<N,types>::type;
template<template<class>class Target,unsigned N,class types>
struct nth_apply;
template<template<class>class Target,unsigned N,class...Ts>
struct nth_apply<Target,N,types<Ts...>>{
typedef Target<type_at_t<N,types<Ts...>>> type;
};
template<template<class>class Target,unsigned N,class types>
using nth_apply_t=typename nth_apply<Target,N,types>::type;
This is the type that produces the function pointers for us:
template<class T>struct shared_maker{
template<class...Args>
std::shared_ptr<T> operator()(Args&&...args)const{
return std::make_shared<T>(std::forward<Args>(args)...);
}
template<class R, class... Args>
operator Type<R(Args...)>*() const{
return [](Args... args)->R{
return shared_maker{}(std::forward<Args>(args)...);
};
}
};
Here is what we do for the actual letter types. We forward declare them:
struct A; struct B; // etc
Stick them into a list of types:
typedef types<A,B> Alphabet_Types;
Now, our simple test Alphabet type:
struct Alphabet {
virtual unsigned get_index() const = 0;
};
And a CRTP helper that gets the index of the letter from its offset into the list of types! The virtual get_indexes is just for debugging:
template<class D>
struct Letter:Alphabet{
static const unsigned index = index_of<D, Alphabet_Types>::value;
virtual unsigned get_index() const override { return index; }
};
Now the signature of our array-producer:
typedef std::shared_ptr<Alphabet> spAlphabet;
std::array<spAlphabet(*)(), Alphabet_Types::value> factories();
Here is how we define our (toy) letter classes:
struct A:Letter<A>{};
struct B:Letter<B>{};
ie, use Letter<> as a CRTP base instead of Alphabet.
The only thing left is to write the function factories.
Index boilerplate. C++1y has a replacement:
template<unsigned...>struct indexes{typedef indexes type;};
template<unsigned Max, unsigned... Is> struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
The actual implementation via a helper function. We get a pack of indexes and expand it, building our std::array of function pointers from our shared_maker above instantiated with an indexed type from the Alphabet_Types we wrote above:
template<unsigned...Is>
std::array<spAlphabet(*)(), Alphabet_Types::value> factories(indexes<Is...>){
return {nth_apply_t<shared_maker,Is,Alphabet_Types>{}...};
}
The actual factories function just forwards to the above helper:
std::array<spAlphabet(*)(), Alphabet_Types::value> factories(){
return factories(make_indexes<Alphabet_Types::value>{});
}
And some trivial test code:
int main() {
std::vector<spAlphabet> vec;
auto builders = factories();
for (int i = 0; i < 2; ++i) {
vec.push_back(builders[i]());
}
for( auto&& ptr:vec ) {
std::cout << ptr->get_index() << "\n";
}
}
Is it possible to have a member variable, that would be able to calculate pointer to the containing object from pointer to itself (in it's method)?
Let's have a foreign call interface wrapped in API like this:
template <typename Class, MethodId Id, typename Signature>
class MethodProxy;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodProxy<Class, Id, ReturnT ()(Arg1T) {
public:
ReturnT operator()(Class &invocant, Arg1T arg1);
};
and similarly for other numbers of arguments from 0 to N. For each class on the foreign side, one C++ class is declared with some traits and this template uses those traits (and more traits for argument types) to find and invoke the foreign method. This can be used like:
Foo foo;
MethodProxy<Foo, barId, void ()(int)> bar;
bar(foo, 5);
Now what I would like to do is define Foo in such way, that I can call like:
Foo foo;
foo.bar(5);
without repeating the signature multiple times. (obviously creating a static member and wrapping the call in a method is simple, right). Well, in fact, that's still easy:
template <typename Class, MethodId Id, typename Signature>
class MethodMember;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodMember<Class, Id, ReturnT ()(Arg1T) {
MethodProxy<Class, Id, Signature> method;
Class &owner;
public:
MethodMember(Class &owner) : owner(owner) {}
ReturnT operator()(Arg1T arg1) { return method(owner, arg1); }
};
That however means the object will end up containing many copies of pointer to itself. So I am looking for a way to make these instances being able to calculate the owner pointer from this and some additional template arguments.
I was thinking along the lines of
template <typename Class, size_t Offset, ...>
class Member {
Class *owner() {
return reinterpret_cast<Class *>(
reinterpret_cast<char *>(this) - Offset);
}
...
};
class Foo {
Member<Foo, offsetof(Foo, member), ...> member;
...
};
but this complains that Foo is incomplete type at the point.
Yes, I know offsetof is supposed to only work for "POD" types, but in practice for any non-virtual member, which this will be, works. I have similarly tried to pass pointer-to-(that)-member (using dummy base-class) in that argument, but that does not work either.
Note, that if this worked, it could also be used to implement C#-like properties delegating to methods of the containing class.
I know how to do the wrapper methods mentioned above with boost.preprocessor, but the argument lists would have to be specified in a weird form. I know how to write macro to generate generic wrappers via templates, but that would probably give poor diagnostics. It would also be trivial if the calls could look like foo.bar()(5). But I'd like to know whether some clever trick would be possible (plus only such clever trick would probably be usable for properties too).
Note: The member type can't be actually specialized on either member pointer to it nor it's offset, because the type must be known before that offset can be assigned. That's because the type can affect required alignment (consider explicit/parcial specialization).
Asking a question is the best way to realize the answer, so this is where I've got:
The offset can't be a template argument, because the type has to be known before the offset can be calculated. So it has to be returned by a function of the argument. Let's add a tag type (dummy struct) and either a put an overloaded function into Owner or directly into the tag. That way we can define everything we need on one place (using a macro). The following code compiles fine with gcc 4.4.5 and prints correct pointer for all members:
#include <cstddef>
#include <iostream>
using namespace std;
(just preamble to make it really compile)
template <typename Owner, typename Tag>
struct offset_aware
{
Owner *owner()
{
return reinterpret_cast<Owner *>(
reinterpret_cast<char *>(this) - Tag::offset());
}
};
This is what's needed to make the object aware of it's own offset. Property or functor or some other code can be added freely to make it useful. Now we need to declare some extra stuff along with the member itself, so let's define this macro:
#define OFFSET_AWARE(Owner, name) \
struct name ## _tag { \
static ptrdiff_t offset() { \
return offsetof(Owner, name); \
} \
}; \
offset_aware<Owner, name ## _tag> name
This defines structure as the tag and puts in a function returning the required offset. Than it defines the data member itself.
Note, that the member needs to be public as defined here, but we could easily add a 'friend' declaration for the tag support protected and private properties. Now let's use it.
struct foo
{
int x;
OFFSET_AWARE(foo, a);
OFFSET_AWARE(foo, b);
OFFSET_AWARE(foo, c);
int y;
};
Simple, isn't it?
int main()
{
foo f;
cout << "foo f = " << &f << endl
<< "f.a: owner = " << f.a.owner() << endl
<< "f.b: owner = " << f.b.owner() << endl
<< "f.c: owner = " << f.c.owner() << endl;
return 0;
}
This prints the same pointer value on all lines. C++ standard does not allow members to have 0 size, but they will only have the size of their actual content or 1 byte if they are otherwise empty compared to 4 or 8 (depending on platform) bytes for a pointer.
1) There's a gcc extension which seemed fitting:
enum{ d_y = __builtin_choose_expr(N,offsetof(X,y),0) };
But it didn't work as expected, even though manual says
"the built-in function does not evaluate the expression that was not chosen"
2) member pointers seemed interesting, eg. offsetof can be defined like this:
template< class C, class T >
int f( T C::*q ) {
return (int)&((*(C*)0).*q);
}
But I still didn't find a way to turn this into constexpr.
3) For now, here's another version:
#include <stdio.h>
#pragma pack(1)
template <class A, int x>
struct B {
int z;
void f( void ) {
printf( "x=%i\n", x );
}
};
#define STRUCT( A ) template< int N=0 > struct A {
#define CHILD( A, N, B, y ) }; template<> struct A<N> : A<N-1> \
{ B<A<N>,sizeof(A<N-1>)> y;
#define STREND };
STRUCT( A )
int x0;
int x1;
CHILD( A,1, B, y );
short x2;
CHILD( A,2, B, z );
char x3;
STREND
typedef A<2> A1;
int main( void ) {
A1 a;
a.y.f();
a.z.f();
}
For now, here's one MS-specific solution, still thinking how to make it more general
#include <stdio.h>
#define offs(s,m) (size_t)&(((s *)0)->m)
#define Child(A,B,y) \
__if_exists(X::y) { enum{ d_##y=offs(X,y) }; } \
__if_not_exists(X::y) { enum{ d_##y=0 }; } \
B<A,d_##y> y;
template <class A, int x>
struct B {
int z;
void f( void ) {
printf( "x=%i\n", x );
}
};
template< class X >
struct A {
int x0;
int x1;
Child(A,B,y);
Child(A,B,z);
};
typedef A<int> A0;
typedef A<A0> A1;
int main( void ) {
A1 a;
a.y.f();
a.z.f();
}
Assuming the calls actually need a reference to the containing object, just store the reference to the owner. Unless you have specific memory profiling evidence that it's causing a significant memory increase to store the extra references, just do it the obvious way.
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
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;
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.
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.
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.
Have you considered just writing a preprocessor to codegen what you need?
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).