B
Brian McGuinness
I have a question about using the STL transform algorithm in a function.
What I want to do is define a group of array classes to represent
APL-style arrays (arrays in which the number of dimensions and the
length of any dimension can be changed at any time). What I currently
plan is to have an abstract base class at the top, to allow
polymorphism, e.g.:
#include "basedefs.h" // Basic data types, e.g. typedef long Integer
typedef vector<Integer> Dimensions;
class Array {
private:
Dimensions shape;
public:
bool IsScalar() { return shape.empty(); }
...
};
and then have a child template array class so that I can have arrays of
characters, booleans, integers, doubles, and pointers (to support arrays
of arrays). The data would be stored as vector<type>, since Bjarne
Stroustrup does not recommend using valarrays for arrays intended to
vary in size after they are created, with sets of array indices resolved
into single indices into the vector as needed, possibly by implementing
a vector version of gslice and so on.
Now, I want to be able to perform a number of operations on these
arrays, following some simple rules regarding compatible dimensions.
For example, for numeric arrays, I want to be able to add two arrays to
produce a new array. For example, add(a, b) would add corresponding
elements of arrays a and b. I define a function to check if the arrays
have identical dimensions, so we know what elements to match up:
bool Conform (const Array &l, const Array &r) {
return l.shape == r.shape;
}
Then, to support a wide variety of binary operations using the same
shape rules, I would like to do something like this:
Array ScalarDyadic (const Array &l, const Array &r, BinaryFunction op) {
Array a;
if (l.IsScalar()) {
transform (r.start(), r.end(), a.start(), bind1st(op, *l.start()));
}
else if (r.IsScalar()) {
transform (l.start(), l.end(), a.start(), bind2nd(op, *r.start()));
}
else if (Conform (l, r)) {
transform (l.start(), l.end(), r.start(), a.start(), op);
}
else throw invalid_dimensions;
return a;
}
But I am not sure how to declare the third (operation) argument,
presumably a functor, so I can pass it to transform(). The STL
documentation seems to imply that there is a general functor type
called BinaryFunction, but I do not see this in the STL header files,
and I have seen no indications that the functors used have to be
derived from a standard class. On the other hand, I could probably
define the arguent as a template, but then I would end up creating a
large number of copies of the ScalarDyadic() function, one for each
operation. In that case it would probably be more efficient to pass
pointers to binary functions in order to avoid using a template, but I
don't know if transform() would support that.
I would appreciate suggestions.
Thanks.
--- Brian
What I want to do is define a group of array classes to represent
APL-style arrays (arrays in which the number of dimensions and the
length of any dimension can be changed at any time). What I currently
plan is to have an abstract base class at the top, to allow
polymorphism, e.g.:
#include "basedefs.h" // Basic data types, e.g. typedef long Integer
typedef vector<Integer> Dimensions;
class Array {
private:
Dimensions shape;
public:
bool IsScalar() { return shape.empty(); }
...
};
and then have a child template array class so that I can have arrays of
characters, booleans, integers, doubles, and pointers (to support arrays
of arrays). The data would be stored as vector<type>, since Bjarne
Stroustrup does not recommend using valarrays for arrays intended to
vary in size after they are created, with sets of array indices resolved
into single indices into the vector as needed, possibly by implementing
a vector version of gslice and so on.
Now, I want to be able to perform a number of operations on these
arrays, following some simple rules regarding compatible dimensions.
For example, for numeric arrays, I want to be able to add two arrays to
produce a new array. For example, add(a, b) would add corresponding
elements of arrays a and b. I define a function to check if the arrays
have identical dimensions, so we know what elements to match up:
bool Conform (const Array &l, const Array &r) {
return l.shape == r.shape;
}
Then, to support a wide variety of binary operations using the same
shape rules, I would like to do something like this:
Array ScalarDyadic (const Array &l, const Array &r, BinaryFunction op) {
Array a;
if (l.IsScalar()) {
transform (r.start(), r.end(), a.start(), bind1st(op, *l.start()));
}
else if (r.IsScalar()) {
transform (l.start(), l.end(), a.start(), bind2nd(op, *r.start()));
}
else if (Conform (l, r)) {
transform (l.start(), l.end(), r.start(), a.start(), op);
}
else throw invalid_dimensions;
return a;
}
But I am not sure how to declare the third (operation) argument,
presumably a functor, so I can pass it to transform(). The STL
documentation seems to imply that there is a general functor type
called BinaryFunction, but I do not see this in the STL header files,
and I have seen no indications that the functors used have to be
derived from a standard class. On the other hand, I could probably
define the arguent as a template, but then I would end up creating a
large number of copies of the ScalarDyadic() function, one for each
operation. In that case it would probably be more efficient to pass
pointers to binary functions in order to avoid using a template, but I
don't know if transform() would support that.
I would appreciate suggestions.
Thanks.
--- Brian