By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,813 Members | 1,252 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,813 IT Pros & Developers. It's quick & easy.

class similar to a function object?

P: n/a
Suppose I have a datastructure (actually it's a graph) with one template
parameter (the property P for each edge and vertex):

struct graph<P>;
struct vertex<P>;
struct edge<P>;

I also have an algorithm that modifies this datastructure. The basic
outline of the algorithm is independent of the type of property. So I
implemented a generic version of the algorithm and a function object for
each type of property I need. In this way, adding a new property
involves simply defining the property and implementing the function
object. And that works great, however I have a question about the
function object, which looks more or less like this:

template <typename P>
struct function_object {
// Initialization
void initialize(region<P>& r) const;
void initialize(edge<P>& e) const;
// Evaluation
double evaluate(const edge<P>& e) const;
};

As you can see I declared it with a template parameter (and add no
implementation). For each type of property I add a specialization (with
an implementation of course).

struct my_property;

template <>
struct function_object<my_property{
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

But I could as well have done this without using "function_object". Are
there pros and/or contras against this design? Initially, my idea was to
add only a specialization of the member functions only, and not the
whole class, but that doesn't work.
Aug 25 '06 #1
Share this Question
Share on Google+
17 Replies


P: n/a
Jef Driesen wrote:
Suppose I have a datastructure (actually it's a graph) with one
template parameter (the property P for each edge and vertex):

struct graph<P>;
struct vertex<P>;
struct edge<P>;
You mean, probably

template<class Pstruct graph;
template<class Pstruct vertex;
template<class Pstruct edge;
I also have an algorithm that modifies this datastructure.
You mean, the graph struct (and all related)?
The basic
outline of the algorithm is independent of the type of property. So I
implemented a generic version of the algorithm and a function object
for each type of property I need. In this way, adding a new property
involves simply defining the property and implementing the function
object. And that works great, however I have a question about the
function object, which looks more or less like this:

template <typename P>
struct function_object {
// Initialization
void initialize(region<P>& r) const;
void initialize(edge<P>& e) const;
// Evaluation
double evaluate(const edge<P>& e) const;
};

As you can see I declared it with a template parameter (and add no
implementation). For each type of property I add a specialization
(with an implementation of course).

struct my_property;

template <>
struct function_object<my_property{
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

But I could as well have done this without using "function_object".
Are there pros and/or contras against this design? Initially, my idea
was to add only a specialization of the member functions only, and
not the whole class, but that doesn't work.
What doesn't work?

template<>
void
function_object<my_property>::initialize(region<my _property>& r) const
{
// blah
}

See FAQ 5.8.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 25 '06 #2

P: n/a
Jef Driesen wrote:
Suppose I have a datastructure (actually it's a graph) with one template
parameter (the property P for each edge and vertex):

struct graph<P>;
struct vertex<P>;
struct edge<P>;
Not using boost::graph, then.
I also have an algorithm that modifies this datastructure. The basic
outline of the algorithm is independent of the type of property. So I
implemented a generic version of the algorithm and a function object for
each type of property I need.
There is a one-to-one relation between function object and property?
Or are there properties for which you could have multiple function
objects?

I.e. the sort algorithm accepts multiple function objects per type.
I have a question about the function object, which looks like this:

template <typename P>
struct function_object {
// Initialization
void initialize(region<P>& r) const;
void initialize(edge<P>& e) const;
// Evaluation
double evaluate(const edge<P>& e) const;
};
Usually initialization is done in the constructor, of course. And
evaluate
is usually named operator(). You might want to inherit from
std::unary_function
to make it more STL-compatible.
For each type of property I add a specialization with an implementation.

struct my_property;

template <>
struct function_object<my_property{
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

But I could as well have done this without using "function_object". Are
there pros and/or contras against this design?
Pro: you can use function_object<Pas a default parameter to the
algorithm.
cf. std::less<Tfor std::sort.
Contra: it's not compatible with STL or boost::graph.
Initially, my idea was to add only a specialization of the member functions
only, and not the whole class, but that doesn't work.
Simple solution that often works: forward to a free function template,
specialize/
overload that.

HTH,
Michiel Salters

Aug 25 '06 #3

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote:
>Suppose I have a datastructure (actually it's a graph) with one
template parameter (the property P for each edge and vertex):

struct graph<P>;
struct vertex<P>;
struct edge<P>;

You mean, probably

template<class Pstruct graph;
template<class Pstruct vertex;
template<class Pstruct edge;
Of course.
>I also have an algorithm that modifies this datastructure.

You mean, the graph struct (and all related)?
That is correct.
>The basic
outline of the algorithm is independent of the type of property. So I
implemented a generic version of the algorithm and a function object
for each type of property I need. In this way, adding a new property
involves simply defining the property and implementing the function
object. And that works great, however I have a question about the
function object, which looks more or less like this:

template <typename P>
struct function_object {
// Initialization
void initialize(region<P>& r) const;
void initialize(edge<P>& e) const;
// Evaluation
double evaluate(const edge<P>& e) const;
};

As you can see I declared it with a template parameter (and add no
implementation). For each type of property I add a specialization
(with an implementation of course).

struct my_property;

template <>
struct function_object<my_property{
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

But I could as well have done this without using "function_object".
Are there pros and/or contras against this design? Initially, my idea
was to add only a specialization of the member functions only, and
not the whole class, but that doesn't work.

What doesn't work?
Providing only implementations for the initialize/evaluate functions
(without a declaring the full class template <struct
function_object<my_propertyabove). Because I think that is not allowed
by the C++ language and it will make it impossible to add different
member variables for each type of property.

template <>
struct function_object<my_property1{
int m_data; // suppose I need ints here
}

template <>
struct function_object<my_property2{
double m_data; // suppose I need doubles here
}

But that (or writing the code) was not my main problem (because i
already have it working. I was wondering if there is an advantage over
doing something like this:

struct my_function_object {
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

e.g., without using the templated "function_object" from my first post?
Aug 25 '06 #4

P: n/a
Jef Driesen wrote:
[..]
But that (or writing the code) was not my main problem (because i
already have it working. I was wondering if there is an advantage over
doing something like this:

struct my_function_object {
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

e.g., without using the templated "function_object" from my first
post?
Does 'my_function_object' have any data members (any state)? So far
nothing says that the functions need to be (a) members of a class and
(b) non-static members of that class.

What does 'my_function_object' do?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 25 '06 #5

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote:
>[..]
But that (or writing the code) was not my main problem (because i
already have it working). I was wondering if there is an advantage over
doing something like this:

struct my_function_object {
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

e.g., without using the templated "function_object" from my first
post?

Does 'my_function_object' have any data members (any state)? So far
nothing says that the functions need to be (a) members of a class and
(b) non-static members of that class.

What does 'my_function_object' do?
One of the properties is something like this:

struct my_property {
matrix<doublealpha, mu;
double lambda;
}

The other one has two alpha's and two mu's (for horizontal and vertical
directions).

After constructing the graph, all properties have default values
(default constructor). Simply because the data needed to create the
graph is not the same as the data to calculate the properties, and is
also equal for all kind of properties. Only the algorithm needs those
properties to do its job. That's why I have those two initialize
functions. It also needs to be able to compare two vertices (=edge) and
sort edges. The evaluate function is used for that.

The my_function_object's have several data members. The first one
contains basically one 3D image and the other one two such images.

BTW, in the code from my first post, I mentioned both a vertex and a
region class, but those are the same. In my application a vertex is a
region of image pixels, hence the different name.
Aug 25 '06 #6

P: n/a
"Jef Driesen" <je********@hotmail.com.invalidwrote...
Victor Bazarov wrote:
>Jef Driesen wrote:
>>[..]
But that (or writing the code) was not my main problem (because i
already have it working). I was wondering if there is an advantage over
doing something like this:

struct my_function_object {
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

e.g., without using the templated "function_object" from my first
post?

Does 'my_function_object' have any data members (any state)? So far
nothing says that the functions need to be (a) members of a class and
(b) non-static members of that class.

What does 'my_function_object' do?

[..]

The my_function_object's have several data members. The first one contains
basically one 3D image and the other one two such images.

BTW, in the code from my first post, I mentioned both a vertex and a
region class, but those are the same. In my application a vertex is a
region of image pixels, hence the different name.
I am still not convinced that you actually need a class
'my_function_object'.
All you need it for is to calculate something. It doesn't seem to need any
state. You can have separate functions and pass your 3D images to them as
arguments.

If you're struggling with instantiating the function_object thingamajig,
just get rid of it and putt the 'initialize' and 'evaluate' functions out
and make them templates (if necessary, of which I am not convinced either).
Then specialize them, if you need that.

Don't rush to reply. Think about it a bit. It is possible that you have
not provided enough information for me to understand why you need those
functions in a class. It doesn't mean you don't need them in a class, it
just means I don't see it yet. Perhaps you could describe your problem
from a slightly different angle, and it will open up to me (and to you).
So far you have some properties and unrelated algorithms which you want
OOH to unify under a class template and OTOH break apart by specialising.
And hereby lies the problem, methinks.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 25 '06 #7

P: n/a
Mi*************@tomtom.com wrote:
Jef Driesen wrote:
>Suppose I have a datastructure (actually it's a graph) with one template
parameter (the property P for each edge and vertex):

struct graph<P>;
struct vertex<P>;
struct edge<P>;

Not using boost::graph, then.
At some point, I considered using it, but I already had a more or less
working implementation and decided not to rewrite everything using
boost::graph.
>I also have an algorithm that modifies this datastructure. The basic
outline of the algorithm is independent of the type of property. So I
implemented a generic version of the algorithm and a function object for
each type of property I need.

There is a one-to-one relation between function object and property?
Or are there properties for which you could have multiple function
objects?

I.e. the sort algorithm accepts multiple function objects per type.
Each property has its own function object, because they are calculated
from different kind of data.
>I have a question about the function object, which looks like this:

template <typename P>
struct function_object {
// Initialization
void initialize(region<P>& r) const;
void initialize(edge<P>& e) const;
// Evaluation
double evaluate(const edge<P>& e) const;
};

Usually initialization is done in the constructor, of course.
The problem is that the graph does not know how to calculate properties.
And I also need the graph itself to calculate the properties. During
construction of the graph (and thus also the regions), I can't calculate
the properties. (I think it can be done if I really want, but I'm afraid
it will be too slow incrementally updating matrices compared to doing it
once in a batch).
And evaluate
is usually named operator(). You might want to inherit from
std::unary_function
to make it more STL-compatible.
I also need sorting, and for that I created a simple helper function
object in STL-style.
>For each type of property I add a specialization with an implementation.

struct my_property;

template <>
struct function_object<my_property{
// Initialization
void initialize(region<my_property>& r) const;
void initialize(edge<my_property>& e) const;
// Evaluation
double evaluate(const edge<my_property>& e) const;
};

But I could as well have done this without using "function_object". Are
there pros and/or contras against this design?

Pro: you can use function_object<Pas a default parameter to the
algorithm.
cf. std::less<Tfor std::sort.
Isn't that almost the same as what I have now?

template <typename P>
void apply_algorithm(graph<P>& g, const function_object<P>& p)
Contra: it's not compatible with STL or boost::graph.
Since I'm not using boost::graph, that disadvantage is not so important.
>Initially, my idea was to add only a specialization of the member functions
only, and not the whole class, but that doesn't work.

Simple solution that often works: forward to a free function template,
specialize/
overload that.
I didn't even think about that. But that will not work if the different
function objects need different member variables.
Aug 25 '06 #8

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote...
>[..]

I am still not convinced that you actually need a class
'my_function_object'.
All you need it for is to calculate something. It doesn't seem to need any
state. You can have separate functions and pass your 3D images to them as
arguments.
If I had separate functions, how would my algorithm know about the 3D
images? And also which variant to call, the one with only one 3D image
as parameter, or the one with two 3D images? With 'my_function_object',
I can add them as member variables and have a version which takes one 3D
image in the constructor and one with two 3D images. And then pass the
function object (which knows how to do the calculations and has all the
extra data) and the graph (which knows the layout of the regions and its
pixels) to my algorithm (where everything is glued together).
If you're struggling with instantiating the function_object thingamajig,
just get rid of it and putt the 'initialize' and 'evaluate' functions out
and make them templates (if necessary, of which I am not convinced either).
Then specialize them, if you need that.

Don't rush to reply. Think about it a bit. It is possible that you have
not provided enough information for me to understand why you need those
functions in a class. It doesn't mean you don't need them in a class, it
just means I don't see it yet. Perhaps you could describe your problem
from a slightly different angle, and it will open up to me (and to you).
So far you have some properties and unrelated algorithms which you want
OOH to unify under a class template and OTOH break apart by specialising.
And hereby lies the problem, methinks.
I will try to reformulate what I'm trying to do.

First step is the constructing of the graph datastructure. The graph is
created from a 2D image, where each pixel is a label. A vertex in the
graph represent a group of pixels with the same label (e.g. a region).
An edge represents a link between two such regions, adjacent to each
other (e.g. neighbors).

Second step is my algorithm. First, all properties for the regions are
calculated. A property for a region is calculated from the corresponding
pixels of one or two 3D images (depending on the type of property)
inside that region. The property itself is some statistical data, like
average vector and covariance matrix. When that is ready, the properties
are calculated for all edges. Properties for an edge are simply the same
statistical properties, but for the union of both regions. They can be
calculated from the properties of the two regions directly (if
possible), or from the underlying 3D image data again. After that edges
are evaluated against a threshold and suitable edges are selected and
sorted according to the return value of the evaluate function. Finally,
the graph is modified and properties are updated again.
Aug 25 '06 #9

P: n/a
Jef Driesen wrote:
Victor Bazarov wrote:
>Jef Driesen wrote...
>>[..]

I am still not convinced that you actually need a class
'my_function_object'.
All you need it for is to calculate something. It doesn't seem to
need any state. You can have separate functions and pass your 3D
images to them as arguments.

If I had separate functions, how would my algorithm know about the 3D
images?
But you don't have a single algorithm, do you? One uses one image, the
other one uses two. So, you need two separate functions, one with one
extra argument of type 'my3Dimage const&', the other needs two extra
arguments.
And also which variant to call, the one with only one 3D image
as parameter, or the one with two 3D images?
Shouldn't the caller know that? You are going to stuff them into your
'function_object' somehow, so at some point the code needs to know how
many images to pass and to whom...
With
'my_function_object', I can add them as member variables and have a
version which takes one 3D image in the constructor and one with two
3D images.
Yes, just like you can have two separate function_object classes. Just
like you can have no classes whatsoever. The code that creates the
objects (right now) can just as well call the 'initialize' functions
without the object, can't it?
And then pass the function object (which knows how to do
the calculations and has all the extra data) and the graph (which
knows the layout of the regions and its pixels) to my algorithm
(where everything is glued together).
Again, it's not a single algorithm, is it? At least so far I've not
see a single algorithm. And if it is a single algorithm, then you are
much better off actually employing polymorphism, IOW, having both of
your 'function_objects' derive from an abstract class and override
your 'initialize' and 'evaluate' functions... Since you've not shown
how your 'my_function_object' instance is going to be used, I have
not formed any opinion on the matter except that it sounds unneededly
complicated.
>If you're struggling with instantiating the function_object
thingamajig, just get rid of it and putt the 'initialize' and
'evaluate' functions out and make them templates (if necessary, of
which I am not convinced either). Then specialize them, if you need
that. Don't rush to reply. Think about it a bit. It is possible that
you
have not provided enough information for me to understand why you
need those functions in a class. It doesn't mean you don't need
them in a class, it just means I don't see it yet. Perhaps you
could describe your problem from a slightly different angle, and it
will open up to me (and to you). So far you have some properties and
unrelated algorithms which you want OOH to unify under a class
template and OTOH break apart by specialising. And hereby lies the
problem, methinks.

I will try to reformulate what I'm trying to do.

First step is the constructing of the graph datastructure. The graph
is created from a 2D image, where each pixel is a label. A vertex in
the graph represent a group of pixels with the same label (e.g. a
region). An edge represents a link between two such regions, adjacent
to each other (e.g. neighbors).
That looks like you need a function like

template<class Pgraph<PcreateGraph(my2Dimage const&);

where 'graph' would contain the vertices and edges necessary to define
your topology. No need for a special functor as of yet.
Second step is my algorithm. First, all properties for the regions are
calculated. A property for a region is calculated from the
corresponding pixels of one or two 3D images (depending on the type
of property) inside that region. The property itself is some
statistical data, like average vector and covariance matrix. When
that is ready, the properties are calculated for all edges.
Properties for an edge are simply the same statistical properties,
but for the union of both regions. They can be calculated from the
properties of the two regions directly (if possible), or from the
underlying 3D image data again. After that edges are evaluated
against a threshold and suitable edges are selected and sorted
according to the return value of the evaluate function. Finally, the
graph is modified and properties are updated again.
Uh... I am not seeing it...

template<class P>
void calculateProperties(region<P>&, my3Dimage const*);

template<class P>
void calculateProperties(edge<P>&, my3Dimage const*);

template<class P>
void calculateProperties(graph<P>&, my3Dimage const*);

The pointer is either one image, or two images or as many as you like,
put into an array. Or you can have a pointer to pointer, which could
be an array of pointers to image...

Where is the need for a 'function_object'?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 25 '06 #10

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote:
>Victor Bazarov wrote:
>>Jef Driesen wrote...
[..]
I am still not convinced that you actually need a class
'my_function_object'.
All you need it for is to calculate something. It doesn't seem to
need any state. You can have separate functions and pass your 3D
images to them as arguments.
If I had separate functions, how would my algorithm know about the 3D
images?

But you don't have a single algorithm, do you? One uses one image, the
other one uses two. So, you need two separate functions, one with one
extra argument of type 'my3Dimage const&', the other needs two extra
arguments.
I only have one algorithm and it takes as argument the graph, the
function object and some less important parameters (like a threshold).

template <typename P>
void apply_algorithm(graph<P>& g, const function_object<P>& p, double
threshold)
{
std::list< edge<P selected;

// Initialize regions
for each region r in g
p.initialize(r);

// Initialize edges
for each edge e in g {
p.initialize(e);
if p.evaluate(e) threshold
selected.push_back(e);
}

// Sort selected edges
selected.sort(compare_edges<P>(p);

// Some more stuff here...
}

Sorting does use an extra helper function object:

template <typename P>
struct compare_edges : public std::binary_function<edge<P>, edge<P>,
bool{
const function_object<P>& m_p;

compare_edges(const function_object<P>& p
: m_p(p) {}

bool operator()(const edge<P>& lhs, const edge<P>& rhs) const
{
return m_p.evaluate(lhs) m_p.evaluate(rhs);
}
};
>And also which variant to call, the one with only one 3D image
as parameter, or the one with two 3D images?

Shouldn't the caller know that? You are going to stuff them into your
'function_object' somehow, so at some point the code needs to know how
many images to pass and to whom...
As you can see, the algorithm itself does not need to know if there were
one or two 3D images. That is handled by my function_object:

struct function_object1 {
image3d m_image;
function_object1(image3d image)
: m_image(image) {}
}

struct function_object2 {
image3d m_image1, m_image2;
function_object1(image3d image1, image3d image2)
: m_image1(image1), m_image2(image2) {}
}

and with different implementations of the evaluate/initialize functions
of course.
>With
'my_function_object', I can add them as member variables and have a
version which takes one 3D image in the constructor and one with two
3D images.

Yes, just like you can have two separate function_object classes. Just
like you can have no classes whatsoever. The code that creates the
objects (right now) can just as well call the 'initialize' functions
without the object, can't it?
I'm not sure what you are trying to say here.
>And then pass the function object (which knows how to do
the calculations and has all the extra data) and the graph (which
knows the layout of the regions and its pixels) to my algorithm
(where everything is glued together).

Again, it's not a single algorithm, is it? At least so far I've not
see a single algorithm. And if it is a single algorithm, then you are
much better off actually employing polymorphism, IOW, having both of
your 'function_objects' derive from an abstract class and override
your 'initialize' and 'evaluate' functions... Since you've not shown
how your 'my_function_object' instance is going to be used, I have
not formed any opinion on the matter except that it sounds unneededly
complicated.
But how can I use polymorphism here? Because their initialize/evaluate
functions have a different type of argument. They are both regions or
edges, but with a different type for the template parameter P.
>>If you're struggling with instantiating the function_object
thingamajig, just get rid of it and putt the 'initialize' and
'evaluate' functions out and make them templates (if necessary, of
which I am not convinced either). Then specialize them, if you need
that. Don't rush to reply. Think about it a bit. It is possible that
you
have not provided enough information for me to understand why you
need those functions in a class. It doesn't mean you don't need
them in a class, it just means I don't see it yet. Perhaps you
could describe your problem from a slightly different angle, and it
will open up to me (and to you). So far you have some properties and
unrelated algorithms which you want OOH to unify under a class
template and OTOH break apart by specialising. And hereby lies the
problem, methinks.
I will try to reformulate what I'm trying to do.

First step is the constructing of the graph datastructure. The graph
is created from a 2D image, where each pixel is a label. A vertex in
the graph represent a group of pixels with the same label (e.g. a
region). An edge represents a link between two such regions, adjacent
to each other (e.g. neighbors).

That looks like you need a function like

template<class Pgraph<PcreateGraph(my2Dimage const&);

where 'graph' would contain the vertices and edges necessary to define
your topology. No need for a special functor as of yet.
That is more or less what I have now, except that createGraph is not
separate function, but a constructor of the graph. You are also correct
that there is no special functor involved here.
>Second step is my algorithm. First, all properties for the regions are
calculated. A property for a region is calculated from the
corresponding pixels of one or two 3D images (depending on the type
of property) inside that region. The property itself is some
statistical data, like average vector and covariance matrix. When
that is ready, the properties are calculated for all edges.
Properties for an edge are simply the same statistical properties,
but for the union of both regions. They can be calculated from the
properties of the two regions directly (if possible), or from the
underlying 3D image data again. After that edges are evaluated
against a threshold and suitable edges are selected and sorted
according to the return value of the evaluate function. Finally, the
graph is modified and properties are updated again.

Uh... I am not seeing it...

template<class P>
void calculateProperties(region<P>&, my3Dimage const*);

template<class P>
void calculateProperties(edge<P>&, my3Dimage const*);

template<class P>
void calculateProperties(graph<P>&, my3Dimage const*);

The pointer is either one image, or two images or as many as you like,
put into an array. Or you can have a pointer to pointer, which could
be an array of pointers to image...

Where is the need for a 'function_object'?
With those calculateProperties functions, I will need to pass the
my3Dimage image(s) to the algorithm too. And that is exactly what I
tried to avoid in the first place. What if I need a third type of
property, which does not need to be calculated from one or more 3D
images, but some other type of data? In this case the algorithm will
stay the same, but that will not be true for the calculateProperties
functions. With the function_object, different data can be passed to the
constructor, but the definition of the evaluate/initialize functions can
remain the same (not the implemantation of course).
Aug 26 '06 #11

P: n/a
Jef Driesen wrote:
[..]
With those calculateProperties functions, I will need to pass the
my3Dimage image(s) to the algorithm too. And that is exactly what I
tried to avoid in the first place. What if I need a third type of
property, which does not need to be calculated from one or more 3D
images, but some other type of data? In this case the algorithm will
stay the same, but that will not be true for the calculateProperties
functions. With the function_object, different data can be passed to
the constructor, but the definition of the evaluate/initialize
functions can remain the same (not the implemantation of course).
OK, I seem to understand better now, thanks for your patience.

Remember I spoke of polymorphism? Forget it. Apparently, due to
your choices, you need your algorithm to be expressed in terms of
templates, so let it be.

I think the problem I had with your inquiry stemmed from the fact
that the centerpoint class template was named so generically (pun
is not intended), "function_object". What you probably should have
named it is "initialiser_and_evaluator". That would take out all
confusion.

And, yes, I think it's a decent design overall. The only side
effect of using templates is an unfortunate need to replicate all
the algorithms for all property types. Had it been written in
terms of abstract graph and edges/regions, and with the use of
some abstract initialiser_and_evaluator, you could have simply
supplied the pointers to those, and implement them as you wish,
even as template specialisations. In that case you'd have only
one algorithm implementation function.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 27 '06 #12

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote:
>[..]
With those calculateProperties functions, I will need to pass the
my3Dimage image(s) to the algorithm too. And that is exactly what I
tried to avoid in the first place. What if I need a third type of
property, which does not need to be calculated from one or more 3D
images, but some other type of data? In this case the algorithm will
stay the same, but that will not be true for the calculateProperties
functions. With the function_object, different data can be passed to
the constructor, but the definition of the evaluate/initialize
functions can remain the same (not the implemantation of course).

OK, I seem to understand better now, thanks for your patience.
No problem at all. Since you took the time to have a look at my problem,
I have to thank you for your patience!
Remember I spoke of polymorphism? Forget it. Apparently, due to
your choices, you need your algorithm to be expressed in terms of
templates, so let it be.

I think the problem I had with your inquiry stemmed from the fact
that the centerpoint class template was named so generically (pun
is not intended), "function_object". What you probably should have
named it is "initialiser_and_evaluator". That would take out all
confusion.
If I had known that in advance :-) What's in a name?
And, yes, I think it's a decent design overall. The only side
effect of using templates is an unfortunate need to replicate all
the algorithms for all property types. Had it been written in
terms of abstract graph and edges/regions, and with the use of
some abstract initialiser_and_evaluator, you could have simply
supplied the pointers to those, and implement them as you wish,
even as template specialisations. In that case you'd have only
one algorithm implementation function.
I don't see how I could use an abstract graph/node/edge class and still
being able to associate a property with the nodes and edges. Is that
even possible without using templates?
Aug 28 '06 #13

P: n/a
Jef Driesen wrote:
[..]
I don't see how I could use an abstract graph/node/edge class and
still being able to associate a property with the nodes and edges. Is
that even possible without using templates?
I am not sure I have the time to into detail, to be honest. If your algo
is so generic that you want to make a template out of it; with a bit of
effort, and by making your graph, edge, and region classes abstract (and
deriving the "real" ones from them) you should be able to also define
your "initialiser_and_evaluator" as an abstract class (and derive the
real ones from it).

Compile-time polymorphism and run-time polymorphism are often symmetrical,
only the run-time polymorphism can be taken a bit further with the help
of plug-ins and shared objects. It does not necessarily mean an advantage
in your case. Just an alternative approach.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 28 '06 #14

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote:
>[..]
I don't see how I could use an abstract graph/node/edge class and
still being able to associate a property with the nodes and edges. Is
that even possible without using templates?

I am not sure I have the time to into detail, to be honest.
No problem, I already appreciated your help very much.
If your algo
is so generic that you want to make a template out of it; with a bit of
effort, and by making your graph, edge, and region classes abstract (and
deriving the "real" ones from them) you should be able to also define
your "initialiser_and_evaluator" as an abstract class (and derive the
real ones from it).
I remember I encountered two kinds of problem when this approach (and
decided to use templates). The first one being that the 3 classes are
more or less nested:

struct graph_base {
struct edge_base {...}
struct node_base {...}
...
}

That means if want to implement multiple types of graph (for different
properties), which share a lot of functionality (like constructing the
graph from the 2D image), I have to duplicate that code (handwritten,
not machine-generated like templates do). Because in my_graph I should
only create objects from the derived class (e.g. my_edge and store a
pointer to edge_base). And since graph_base doesn't know anything about
the derived classes, I can't implement it there.

struct my_graph : public graph_base {
struct my_edge : public edge_base {/*add properties here*/}
struct my_node : public node_base {/*add properties here*/}
}

Second problem was the initialiser_and_evaluator class

struct initialiser_and_evaluator {
initialize(edge_base& e) const;
initialize(node_base& n) const ;
evaluate(const edge_base& e) const;
}

If I overload this class, the functions will accept only
edge_base/node_base as arguments. And those don't have access to the
properties.

I'm sure there will be solutions for them, but I'm not aware of them.
Compile-time polymorphism and run-time polymorphism are often symmetrical,
only the run-time polymorphism can be taken a bit further with the help
of plug-ins and shared objects. It does not necessarily mean an advantage
in your case. Just an alternative approach.
Finally each one has different (dis)advantages...

The run-time polymorphism would simplify the code in my main() a lot,
because currently I have (lots of) #ifdef's to pick one of the two
templates, which results in two different binaries. It works, but its
messy. Implementing a command line switch would be much easier with the
run-time polymorphism).
Aug 28 '06 #15

P: n/a
Jef Driesen wrote:
Victor Bazarov wrote:
>If your algo
is so generic that you want to make a template out of it; with a bit
of effort, and by making your graph, edge, and region classes
abstract (and deriving the "real" ones from them) you should be able
to also define your "initialiser_and_evaluator" as an abstract class
(and derive the real ones from it).

I remember I encountered two kinds of problem when this approach (and
decided to use templates). The first one being that the 3 classes are
more or less nested:

struct graph_base {
struct edge_base {...}
struct node_base {...}
...
}
No, they don't have to be nested. Stuff them all in a namespace if you
worry about name collisions, but otherwise 'graph', 'edge', and 'node'
are three equal concepts.
That means if want to implement multiple types of graph (for different
properties), which share a lot of functionality (like constructing the
graph from the 2D image), I have to duplicate that code (handwritten,
not machine-generated like templates do).
Uh... And now you do it differently?

If you approach your problem from a normal OOAD point of view, you can
create a neat hierarchy of classes, where you could have your property-
based templates implement some abstract classes. Something like

struct graph_base { // abstract
};

struct graph_from_2d_image : graph_base { // still abstract
};

template<class P>
struct graph_2d : graph_from_2d_image { // concrete but
// generic, templated
// on P, which you can
// later instantiate
};

...
template graph_2d<my_special_property>; // instantiation 1
template graph_2d<my_other_special_property>; // instantiation 2
Because in my_graph I should
only create objects from the derived class (e.g. my_edge and store a
pointer to edge_base). And since graph_base doesn't know anything
about the derived classes, I can't implement it there.
I am not sure I understand. *Implement* everything you need in the
derived classes, which should know about other derived classes.
struct my_graph : public graph_base {
struct my_edge : public edge_base {/*add properties here*/}
struct my_node : public node_base {/*add properties here*/}
}
Nope. Break 'em up.
Second problem was the initialiser_and_evaluator class

struct initialiser_and_evaluator {
initialize(edge_base& e) const;
initialize(node_base& n) const ;
evaluate(const edge_base& e) const;
}

If I overload this class,
"Overload"? Do you mean, create a hierarchy of them?
the functions will accept only
edge_base/node_base as arguments. And those don't have access to the
properties.
They shouldn't have to. All those things should be polymorphic.
I'm sure there will be solutions for them, but I'm not aware of them.
You're allowed to make implementations aware of each other, you don't
need to make base classes to be aware of the derived ones, if you design
your hierarchy (and the functionality) correctly.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 28 '06 #16

P: n/a
Victor Bazarov wrote:
Jef Driesen wrote:
>Victor Bazarov wrote:
>>If your algo
is so generic that you want to make a template out of it; with a bit
of effort, and by making your graph, edge, and region classes
abstract (and deriving the "real" ones from them) you should be able
to also define your "initialiser_and_evaluator" as an abstract class
(and derive the real ones from it).
I remember I encountered two kinds of problem when this approach (and
decided to use templates). The first one being that the 3 classes are
more or less nested:

struct graph_base {
struct edge_base {...}
struct node_base {...}
...
}

No, they don't have to be nested. Stuff them all in a namespace if you
worry about name collisions, but otherwise 'graph', 'edge', and 'node'
are three equal concepts.
You are right, but conceptually, they are nested. For instance a node
should only exist inside a graph, because a node contains links (the
edges) to other nodes from the same graph. At least in my implementation
(where the edge is also reduced to an auxiliary class for my algorithm):

struct graph {
std::vector<node*m_regions;
};
struct node {
std::list<node*m_neighbours;
};
struct edge{
node *m_source, *m_target;
};
>That means if want to implement multiple types of graph (for different
properties), which share a lot of functionality (like constructing the
graph from the 2D image), I have to duplicate that code (handwritten,
not machine-generated like templates do).

Uh... And now you do it differently?
With the template based approach, I have no (handwritten) duplicate
code. There is one only one algorithm to construct the graph from the 2D
image and only one algorithm:

template <typename P>
graph<p>::graph(const image2d&)
{
// Construct graph here
}

template <typename P>
void apply_algorithm(graph<P>& g, const initialiser_and_evaluator<P>& p,
double threshold)
{
// Algorithm goes here
}

Only the initialiser_and_evaluator objects are obviously different for
each type of property P.
If you approach your problem from a normal OOAD point of view, you can
create a neat hierarchy of classes, where you could have your property-
based templates implement some abstract classes. Something like

struct graph_base { // abstract
};

struct graph_from_2d_image : graph_base { // still abstract
};

template<class P>
struct graph_2d : graph_from_2d_image { // concrete but
// generic, templated
// on P, which you can
// later instantiate
};

...
template graph_2d<my_special_property>; // instantiation 1
template graph_2d<my_other_special_property>; // instantiation 2
>Because in my_graph I should
only create objects from the derived class (e.g. my_edge and store a
pointer to edge_base). And since graph_base doesn't know anything
about the derived classes, I can't implement it there.

I am not sure I understand. *Implement* everything you need in the
derived classes, which should know about other derived classes.
I was actually thinking a little different here. In your example above,
to graph_from_2d_image would have been a concrete class with a
constructor to create the graph from the 2D image:

graph_from_2d_image::graph_from_2d_image(const image2d&)
{
// Create nodes and edges here.
}

But this code does not know which type of nodes/edges to create, because
they are not known at this point yet. So I need to move that code to the
graph_2d class?
>struct my_graph : public graph_base {
struct my_edge : public edge_base {/*add properties here*/}
struct my_node : public node_base {/*add properties here*/}
}

Nope. Break 'em up.
>Second problem was the initialiser_and_evaluator class

struct initialiser_and_evaluator {
initialize(edge_base& e) const;
initialize(node_base& n) const ;
evaluate(const edge_base& e) const;
}

If I overload this class,

"Overload"? Do you mean, create a hierarchy of them?
That's indeed what I mean. All those technical terms can be confusing
sometimes...
>the functions will accept only
edge_base/node_base as arguments. And those don't have access to the
properties.

They shouldn't have to. All those things should be polymorphic.
Suppose I do:

template <typename P>
struct edge : public edge_base {
P m_property;
};

template <typename P>
struct my_i_and_e: public initialiser_and_evaluator {
initialize(edge_base& e) const;
initialize(node_base& n) const ;
evaluate(const edge_base& e) const;
};

Now in the my_i_and_e::initialize function, I have only access to an
edge_base, even when an edge<Pwas passed. How can I modify it's
property (which is the purpose of that function)?
>I'm sure there will be solutions for them, but I'm not aware of them.

You're allowed to make implementations aware of each other, you don't
need to make base classes to be aware of the derived ones, if you design
your hierarchy (and the functionality) correctly.
Aug 29 '06 #17

P: n/a
Jef Driesen wrote:
Victor Bazarov wrote:
>[.. node does not have to be inner class of graph ..]

You are right, but conceptually, they are nested. For instance a node
should only exist inside a graph, because a node contains links (the
edges) to other nodes from the same graph.
Are you sure you're not confusing the containment of objects with the
containment of concepts? Yes, a node is contained inside the graph,
but the class 'node' does not have to be an inner class of 'graph'.

I am not talking about the OOAD principles here. If you have a language
problem due to the fact that 'node' is a member of 'graph', don't make
it a member.
[...]
>>Because in my_graph I should
only create objects from the derived class (e.g. my_edge and store a
pointer to edge_base). And since graph_base doesn't know anything
about the derived classes, I can't implement it there.

I am not sure I understand. *Implement* everything you need in the
derived classes, which should know about other derived classes.

I was actually thinking a little different here. In your example
above, to graph_from_2d_image would have been a concrete class with a
constructor to create the graph from the 2D image:

graph_from_2d_image::graph_from_2d_image(const image2d&)
{
// Create nodes and edges here.
}

But this code does not know which type of nodes/edges to create,
because they are not known at this point yet. So I need to move that
code to the graph_2d class?
I am not sure about that. Generally, constructors are not polymorphic,
and if you need to (and only if you need to), you could create your
objects using the default c-tor and then "initialise" or "finalise"
using a virtual function. I was talking more of something like

// somewhere
image_base *pimage = image_producer->get_image();
graph_base *pgraph = graph_producer->get_new_graph(pimage);

you can have a polymorphic 'graph_producer' that resolves to some kind
of graph_2d producer or graph_3d producer, at run time. Any type of
polymorphism can be taken to extreme, of course.
[..]
>>the functions will accept only
edge_base/node_base as arguments. And those don't have access to the
properties.

They shouldn't have to. All those things should be polymorphic.

Suppose I do:

template <typename P>
struct edge : public edge_base {
P m_property;
};

template <typename P>
struct my_i_and_e: public initialiser_and_evaluator {
initialize(edge_base& e) const;
initialize(node_base& n) const ;
evaluate(const edge_base& e) const;
};

Now in the my_i_and_e::initialize function, I have only access to an
edge_base, even when an edge<Pwas passed. How can I modify it's
property (which is the purpose of that function)?
I don't know. You can cast your 'edge_base' to 'derived_edge', which
should be fine since you're in the derived class, and it can be aware
of other derived classes that work with it.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Aug 29 '06 #18

This discussion thread is closed

Replies have been disabled for this discussion.