Defining Attachment Patterns in C ++
I am overusing C ++ templates a bit and I am having a hard time figuring things out. Let's say I have two types that really need to inherit from the base type, but for speed reasons I can't afford the overhead of a virtual function (I've been comparing this and virtual calls are ruining things for me!).
Firstly, here are the two classes I have
template<class DataType> class Class1
{
//Lots of stuff here
}
template<Class DataType> class Class2
{
//The same stuff as in Class1, but implemented differently
}
In typical design oo Class1
and Class2
inherit from IInterface
and I could have a function that looks like
DoStuff(IInterface& MyInterface)
{
}
But I can't do it, so I did it
template <class C>
DoStuff(C& c)
{
}
I know this is not very pretty since there is nothing (at the compiler level) to ensure that Class1
both Class2
implement the same interface, but for speed reasons I am breaking some rules.
I'd love to create a callback function on DoStuff
, but I can't figure out how to make it work with templates (especially since it's hidden there.
For example, this is working right now
DoStuff(char* filename)
{
switch (//figure out the type i need to make)
{
case 1: return DoStuff(Class1<int>(filename));
case 2: return DoStuff(Class1<double>(filename));
}
}
template<class DataType>
DoStuff(DataType* pdata)
{
return DoStuff(Class2<DataType>(pdata));
}
template<class C>
DoStuff(C c)
{
c.Print();
}
Now I know what you are asking, why use Class1
u Class2
? Well, the main difference between working with a file and working with memory is so great that it makes sense to have different classes for different input types (and not just overload the constructor and behave differently for different inputs). Again, I did this for comparison, and it's much faster to have special cases handled in their own classes rather than case
s / if
in each function.
So what I would like to do is hide most of this implementation from junior developers, I don't want them to have to create three different overloads DoStuff
to handle different inputs. Ideally I would set up some type of callback with a #defines
and all they have to do is something like creating a named class DoStuff
and overloading the operator ()
and executing the function.
The problem I am facing is that the function DoStuff
that does this job is only templatized from <class C>
but itself scripted with help <class DataType>
and all I canβt figure out is how to go all around in a general way. For example, I cannot use template <class C<DataType>>
or template<template< class DataType> class C>
. It just won't compile.
Does anyone have a good trick to have a generic call, either a function or a functor (I don't care), with this nested template? Basically, I want something where I can write a generic function that doesn't care about the class holding the data, and calls it a mostly generic function that determines which class to use.
BigSwitch(CallBack,Inputs)
{
switch(//something)
{
case 1: return CallBack(Class1<Type>(Inputs))
case 2: return CallBack(Class2<Type>(Inputs))
}
}
This way I can write one function BigSwitch
and other people will write CallBack functions.
Any ideas?
EDIT for clarification for Jalf:
I have two very similar classes, Class1
and Class2
, which basically represent the same data type, but the data store is significantly different. To make it more concrete, I use a simple example Class1
- a simple array, and Class2
looks like an array, but instead of storing in the memory are stored in a file (because it is too large to be placed in memory) so I'm going to call them MemArray
and FileArray
now. So let's say I want the sum of the arrays. I can do something like this
template <class ArrayType, class ReturnType>
ReturnType Sum(ArrayType A)
{
ReturnType S=0;
for (int i=A.begin();i<A.end();++i)
{
S+=A[i];
}
return S;
}
But now I need a way to load real data into an array. If it is a memory based array I would do this
MemArray<DataType> M(pData);
and if it is file-baaed i would do this
FileArray<DataType> F(filename);
and both of these calls are valid (since the compiler generates both code paths at compile time)
double MS=Sum<MemArray<DataType>,double>(M);
double FS=Sum<FileArray<DataType>,double>(F);
This all assumes that I know what the DataType is, but for a file-based array, I might not know the data type until I open the file and ask for a header to see what data is in the array.
double GetSum(char* filename)
{
int DataTypeCode=GetDataTypeCode(filename);
switch (DataTypeCode)
{
case 1: return Sum<FileArray<int>,double>(FileArray<int>(filename));
case 2: return Sum<FileArray<double>,double>(FileArray<double>(filename));
}
}
template <class DataType>
double GetSum(DataType* pData)
{
return Sum<MemArray<DataType>,double>(MemArray<DataType>(pData));
}
This all works, but it requires writing two overloaded functions GetX
and a function X
for everything I would like to do. functions GetX
are basically the same code every time except the called one X
. So I would like to write something like
double GetX(CallBackType X, char* filename)
{
int DataTypeCode=GetDataTypeCode(filename);
switch (DataTypeCode)
{
case 1: return X<FileArray<int>,double>(FileArray<int>(filename));
case 2: return X<FileArray<double>,double>(FileArray<double>(filename));
}
}
template <class DataType>
double GetX(CallBackType, DataType* pData)
{
return X<MemArray<DataType>,double>(MemArray<DataType>(pData));
}
so I can call
GetX(Sum,filename)
and then when someone wants to add a new function, all they have to do is write the function and call
GetX(NewFunction,filename)
I'm just looking for a way to write my overloaded functions GetX
and my functions X
so that I can abstract the input / storage path from the real algorithms. This is usually not a hard problem, I just have problems because the function X
contains a template argument that is itself templated. template<class ArrayType>
also has a hidden one ArrayType<DataType>
hidden there. The compiler is not happy with this.
a source to share
Focusing on the original part of your question (why aren't you just using inheritance):
The usual way of compile time polymorphism and giving access to derived class members through the base class is through CRTP .
template <typename T>
class IInterface {
void DoStuff() {
void static_cast<T*>(this)->DoStuff()
}
};
class Class1 : IInterface<Class1> {
void DoStuff(){...}
}
Will this solve your problem?
Edit: By the way, I'm glad I can help, but next time try to structure your question a little more.
I didn't really know what you were asking, so it was just a punch in the dark based on the first three lines of your question.;)
You never explain what you are trying to achieve, just what looks like a broken workaround. Start by posing a problem, as this is what we really need to know. You can then provide information on your current workarounds. And add some context when posting your code. Where is DoStuff () called from and why should junior developers define them? (You've already done that, haven't you?)
What would junior developers say with this code in the first place?
And it's confusing that you are providing specific cases (1 and 2) but not the switch statement itself (// something)
Next time you will get much more (and better and faster) answers if you try to make it easier to answer the question. :)
a source to share
Regarding your question about "generic callback", you can use boost :: function , but mostly uses virtual functions under the covers (it may not be the case, but at least a similar concept), so the performance difference you are looking for is , won't (in fact, the boost :: function will probably be slower due to heap allocation).
a source to share