static polymorphism and Factory Pattern

A

alexander.stippler

Hello,

I need on the one hand static polymorphism for efficiency concerns,
e.g.

template <typename P>
class Problem
{
public:
const P &
problem() const { return static_cast<const P &>(*this); }

P &
problem() { return static_cast<P &>(*this); }

void
method1() { this->problem().method1(); }

// .... other methods
};

template <typename T>
class SpecificProblem
: public Problem<SpecificProblem<T> >
{
public:
void
method1() {}
};

There is one specific interface all derived classes have to share, so
this CRTP-method is well suited.
But I also want the following: Which specific problem I have to
instantiate is given by some external run-time value, let's say by a
string. Ok, so I could use the Factory pattern for instatiation. But
for this pattern I need some common base class as return type for the
created object. Let us for the moment consider we have this type
'ProblemType *' (it cannot be 'Problem *'!). There is no way back such
that I could use the structure above, i.e. call 'method1()' efficiently
(or at all). Any solutions.
I need:
several classes all sharing a common interface.
a method like factory pattern to instantiate the classes given a
'string value'
efficient usage of the class's methods afterwards (no virtual
function calls!)
I fear, that's too many requirements to fulfill at the same time.

Best regards,
Alex
 
J

Josh Mcfarlane

I need:
several classes all sharing a common interface.
a method like factory pattern to instantiate the classes given a
'string value'
efficient usage of the class's methods afterwards (no virtual
function calls!)
I fear, that's too many requirements to fulfill at the same time.

Why can you not make a virtual function call?

Josh McFarlane
 
A

alexander.stippler

Josh said:
Why can you not make a virtual function call?

Josh McFarlane

because the functions are very simple, called thousands of times and
the virtual function overhead would be performance critical.
 
B

BigBrian

because the functions are very simple, called thousands of times and
the virtual function overhead would be performance critical.

It seems most people who make this claim do so on their belief and not
on fact. Have you tested your statement by actual measurement?

Usually, if you eliminate the polymorphism, you will end up with a
switch statement in your code. For efficiency, both are about the
same. But using virtual functions will produce code that is cleaner
and easier to maintain and extend.

-Brian
 
A

Arne Adams

Hello,

I need on the one hand static polymorphism for efficiency concerns,
But I also want the following: Which specific problem I have to
instantiate is given by some external run-time value, let's say by a
string.

If you could put the creation and the handling of the problem into 1
function it could be done like this:
(But it is no longer evident what the Baseclass Problem<T> is for)

#include <map>
#include <string>


template <typename P>
class Problem
{
public:
const P &
problem() const { return static_cast<const P &>(*this); }

P &
problem() { return static_cast<P &>(*this); }

void
method1() { this->problem().method1(); }

// .... other methods
};

template <typename T>
class SpecificProblem
: public Problem<SpecificProblem<T> >
{
public:
void method1() {}
};

typedef void (*CreateAndSolveFunction)();

template<typename P> void Solve(Problem<P>& trouble)
{
trouble.method1();
}

template<typename ConcreteTrouble> void DoCreateAndSolve()
{
SpecificProblem<ConcreteTrouble> concreteTrouble;
Solve(concreteTrouble);
}

typedef std::map<std::string, CreateAndSolveFunction> SolvableProblems;

SolvableProblems InitSolvableProblems()
{
SolvableProblems result;
result[std::string("int")]=&DoCreateAndSolve<int>;
return result;
}

void CreateAndSolve(std::string const& problemId)
{
static const SolvableProblems solvableProblems = InitSolvableProblems();
SolvableProblems::const_iterator where =
solvableProblems.find(problemId);
if(where != solvableProblems.end())
(*where->second)();
}

int main()
{
CreateAndSolve("int");
}

Regards,
Arne
 
A

alexander.stippler

BigBrian said:
It seems most people who make this claim do so on their belief and not
on fact. Have you tested your statement by actual measurement?

Yes. I have.
Usually, if you eliminate the polymorphism, you will end up with a
switch statement in your code. For efficiency, both are about the
same. But using virtual functions will produce code that is cleaner
and easier to maintain and extend.

-Brian

I do not see how my polymorphism problem can be mapped to switch
statements. You mean a switch depending on the type? If yes, what does
this have to do with my problem?
 
A

alexander.stippler

Arne said:
Hello,

I need on the one hand static polymorphism for efficiency concerns,
But I also want the following: Which specific problem I have to
instantiate is given by some external run-time value, let's say by a
string.

If you could put the creation and the handling of the problem into 1
function it could be done like this:
(But it is no longer evident what the Baseclass Problem<T> is for)

#include <map>
#include <string>


template <typename P>
class Problem
{
public:
const P &
problem() const { return static_cast<const P &>(*this); }

P &
problem() { return static_cast<P &>(*this); }

void
method1() { this->problem().method1(); }

// .... other methods
};

template <typename T>
class SpecificProblem
: public Problem<SpecificProblem<T> >
{
public:
void method1() {}
};

typedef void (*CreateAndSolveFunction)();

template<typename P> void Solve(Problem<P>& trouble)
{
trouble.method1();
}

template<typename ConcreteTrouble> void DoCreateAndSolve()
{
SpecificProblem<ConcreteTrouble> concreteTrouble;
Solve(concreteTrouble);
}

typedef std::map<std::string, CreateAndSolveFunction> SolvableProblems;

SolvableProblems InitSolvableProblems()
{
SolvableProblems result;
result[std::string("int")]=&DoCreateAndSolve<int>;
return result;
}

void CreateAndSolve(std::string const& problemId)
{
static const SolvableProblems solvableProblems = InitSolvableProblems();
SolvableProblems::const_iterator where =
solvableProblems.find(problemId);
if(where != solvableProblems.end())
(*where->second)();
}

int main()
{
CreateAndSolve("int");
}

Regards,
Arne

Thanks for your idea. You never have to deal with the concrete
Problem's type at all. Clever. But unfortunately this is not enough in
my situation. I have to be able to pass the ConcreteProblem to
functions as argument. I just considered if virtual functions are
really that evil to my problem, test it and they are!! So I perhaps
have to think about completely different approaches.

Alex
 
A

Arne Adams

Hi,


Thanks for your idea. You never have to deal with the concrete
Problem's type at all. Clever. But unfortunately this is not enough in
my situation. I have to be able to pass the ConcreteProblem to
functions as argument.

Could you post code for what you need to do?

Note that Solve could as well operate directly on the most derived problem
type because Solve is called in a context where that type is statically
known.

Arne
 
A

alexander.stippler

Arne said:
Hi,




Could you post code for what you need to do?

Note that Solve could as well operate directly on the most derived problem
type because Solve is called in a context where that type is statically
known.

Arne

OK. I think code wold be too lengthy. The concept:
- a library providing mainly a special kind of 'Solver'. As input it
needs some
'Problem' given by a) a descrition file (several parameters)
and b) a realization of a class
'SpecificProblem' implementing some methods
which are to be called by the Solver
instantiation and are
problem specific (very frequently
called).
- which specific realization of Problem shoud be used is given by a
string in the description file.
- the main 'Solver' class should be able to pass its argument - the
SpecificProblem - to other
parts implementing the Solver ingredients.

I tend to think, that the CRTP is the thing one could perhaps replace.
The need for efficient function calls for the SpecificProblem is
perhaps easier to fulfill than the combination of CRTP and Factory
methods. Keeping the factory approach one then has to find a way for
efficient realizations of SpecificProblem.

Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,150
Members
46,696
Latest member
BarbraOLog

Latest Threads

Top