I'd like to know what this expression means??
typedef bool (*compareShapes)(const Shape* s1, const Shape* s2);
The Shape
is a class.
I'd like to know what this expression means??
typedef bool (*compareShapes)(const Shape* s1, const Shape* s2);
The Shape
is a class.
You should be using using-statements. It make the very same declaration easier to read:
using compareShapes = bool(*)(const Shape*, const Shape*);
See it now? the type is after the equal sign. It's a pointer to function type.
One could declare it like this too:
// function pointer type --v----------------------------------------------------v
using compareShapes = std::add_pointer_t< bool(const Shape*, const Shape*) >;
// function signature -----^------------------------------^
The function signature is composed like this:
<return-type>( <arguments...> )
When you add the pointer in it, it looks like this:
<return-type>(*)( <arguments...> )
And if you add the pointer name or type name here, add it after the star:
<return-type>(*typeOrPointerName)( <arguments...> )
Well, it's a typedef, so there are two parts - the type, and the new name being defined for it.
The first part is the type:
bool (*)(const Shape* s1, const Shape* s2);
which is a pointer to a function, taking two pointer-to-const-Shape arguments, and returning bool.
The second part is the name of the type: compareShapes
. Admittedly function pointer typedefs are tricky to read, but that's partly just because function pointer syntax isn't used very often.
So, for example, I can write any number of compatible functions:
bool identical(const Shape *a, const Shape *b);
bool strictlyContained(const Shape *a, const Shape *b);
bool topologicallyEquivalent(const Shape *a, const Shape *b);
which tells me whether a
is identical to b
, or wholly inside b
, or whether a
and b
have the same number of holes.
Then, I can write code which works with any comparison, and choose which to use later, like:
compareShapes cmp;
if (shouldUseIdentityComparison()) {
cmp = &identical;
} else if (shouldUseInsideComparison()) {
cmp = &strictlyContained;
} else {
cmp = &topologicallyEquivalent;
// ...
if (cmp(a,b)) {
// they're equal, for whichever comparison we chose above
}
It's probably more common in modern code to either write a template, taking an arbitrary comparator type (as in std::sort
), or to write a non-template function taking std::function<bool(const Shape*, const Shape*)>
, which is more flexible than a raw function pointer.
C doesn't (and earlier versions of C++ didn't) have these facilities, so had to use function pointers. I suspect they're mostly used for backwards-compatibility with older code, and possibly in resource-constrained environments.
compareShapes is alias for function pointer, which accepts 2 const Shape*
and return bool
compareShapes func = [] (const Shape* s1, const Shape* s2) -> bool {
return *s1 == *s2; //something boolean
};
bool result = func(s1, s2);
Or another example, if you already have function:
bool someFunc(const Shape* s1, const Shape* s2) { return true; }
compareShapes funcPtr = someFunc;
bool result = funcPtr(s1, s2);
More about function pointers is available HERE
To add some detail to the comments:
This is a function pointer. The typedef is there to make it easier to use. Ordinarily typedefs have the form "typedef actual_type new_easier_name". Ex:
typedef int i
Obviously that line would never appear in practice. But for more complicated types (especially those involving pointers and templates), using a typedef can make your code much more readable.
This expression is giving the name "compareShapes" to a function pointer type. In this case, that type is a function that takes pointers to two Shape objects and returns a boolean. This way, code to assign a function to the pointer and call it is much more clear.
Here's an example that might appear in practice. Assume Shape has at least two fields: perimeter and area. A user might want to sort on either of them:
#include <vector>
bool perimeterComparison(const Shape* a, const Shape* b){
return a->perimeter <= b->perimeter;
}
bool areaComparison(const Shape* a, const Shape* b){
return a->area <= b->area;
}
//Note the capitalization of CompareShapes to show it is a type, not a variable
typedef bool (*CompareShapes)(const Shape* a, const Shape* b);
void sortShapes(std::vector<Shape*>& shapes, CompareShapes comparison){
//Lazy programming: bubble sort
for(int first = 0; first < shapes.length(); shapes++){
for(int second = first + 1; second < shapes.length(); shapes++){
if(!comparison(shapes[first], shapes[second])){
Shape* temp = shapes[second];
shapes[second] = shapes[first];
shapes[first] = shapes[second];
}
}
}
}
int main(){
//This could just as easily point to perimeterComparison or something else valid
CompareShapes compareFunction = &areaComparison;
std::vector<Shape*> shapes(10);
for(int i = 0; i < 10; i++){
shapes[i] = new Shape(); //Initialize the shapes somehow
}
sortShapes(shapes, compareFunction);
for(int i = 0; i < 10; i++){
cout << shapes[i] << "\n";
}
return 0;
}
You can use cdecl
to interpret such types, but you need to insert struct
before the class names, and replace bool
for it to parse as C code:
cdecl> explain struct bool (*compareShapes)(const struct Shape* , const struct Shape* )
declare compareShapes as pointer to function (pointer to const struct Shape, pointer to const struct Shape) returning struct bool
You then need to mentally undo that transformation, giving
declare
compareShapes
as pointer to function (pointer to constShape
, pointer to constShape
) returningbool
compareShapes
is a function pointer which takes 2 parameter of type (pointer to Shape
) and returns boolean value.
You can assign compareShapes
any function which fits this signature.
So for example,
bool isShapesValid(const Shape* s1, const Shape* s2)
can be assigned:
compareShapes objCompareShapes = &isShapesValid;
typedef bool (*compareShapes)(const Shape* s1, const Shape* s2);
bool CmpShapes(const Shape *s1,const Shape *s2){retunr true;}
compareShapes
is a function prototype (signature) who compares two Shape objects
for example:
class Shape{};
class CTest{
compareShapes m_cmp;
public:
CTest(compareShapes _cmpFunc):m_cmp(_cmpFunc){
printf("m_cmp: %p %s\n",m_cmp,m_cmp(NULL,NULL)?"true":"false");
};
};
void main(){
Ctest tst(&CmpShapes);//we pass CmpShapes address.
}