13

I'd like to know what this expression means??

typedef bool (*compareShapes)(const Shape* s1, const Shape* s2);

The Shape is a class.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
Younès Raoui
  • 211
  • 5
  • 10
  • Isn't it `*compareShapes`? in which case it's a function pointer typedef. – Hatted Rooster Nov 23 '16 at 14:09
  • 1
    seems very much like a function pointer. that means any function, that takes one shape by value and one by pointer, can be assigned to compareShapes. you can achieve generic algorithm with this way. see qsort for an example where this is used. another approach would be a template, see std::sort to see how the same idea is done with a template – jonas_toth Nov 23 '16 at 14:11
  • You may be wondering why it's a declaration of a *pointer* to a function rather than a function itself. The reason is that functions cannot be passed around and returned by value; you can only do that with a pointer to it. – David G Nov 23 '16 at 19:29
  • http://cdecl.org/ – phuclv Nov 24 '16 at 05:25
  • [What does a typedef with parenthesis like “typedef int (f)(void)” mean](http://stackoverflow.com/q/3674200/995714) – phuclv Nov 24 '16 at 05:27

7 Answers7

27

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...> )
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • 1
    Nice clarification! – The Vee Nov 23 '16 at 14:29
  • 4
    Maybe my view is unpopular, but I find the typedef easier to read in many cases, including this one. – Justin Nov 23 '16 at 15:19
  • 6
    Maybe I'm an old fart, but my reaction is "oh god, not _another_ way to write the same damn thing that I have to remember now". – zwol Nov 23 '16 at 22:01
  • 5
    While I'm like "wait, there was an old way? Ugh, that was so ugly. Glad the new way exists" – Guillaume Racicot Nov 23 '16 at 22:03
  • @zwol the good thing with the new one is that you no longer have to remember it, since it's more readable :) – Ciprian Tomoiagă Nov 24 '16 at 10:32
  • Should mention that `std::add_pointer_t` is in ``, beginning with C++11. – Toby Speight Nov 24 '16 at 11:09
  • 2
    The question is "i'm reading code and found this, what is it?", why is the highest rated answer "you should do this instead"? o.O – Weaver Nov 24 '16 at 11:25
  • @StarWeaver because I used the new syntax to help OP understand the old one. And while at it, I recommended OP to simply use the new one. – Guillaume Racicot Nov 24 '16 at 14:22
  • 1
    @CiprianTomoiaga Please understand that my entire career has been spent maintaining gigantic (>10MLOC), _old_ (>20 years of VCS history) programs. I can say with 100% confidence that people like me will _always_ have to know the old form. And now also the new form. */me wanders off muttering something about those damn kids on his lawn* – zwol Nov 25 '16 at 16:37
16

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.

Useless
  • 64,155
  • 6
  • 88
  • 132
12

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

Starl1ght
  • 4,422
  • 1
  • 21
  • 49
6

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;
}
Andrew
  • 518
  • 2
  • 9
  • 4
    "Obviously that line would never appear in practice". MIcrosoft wants a WORD with you. – Revolver_Ocelot Nov 23 '16 at 14:24
  • your example isnt the very best, because this particular example would be even easier too read without using a function pointer at all. imho a better example would be a function that takes e.g. two shapes and a pointer to a comparison function as parameter. – 463035818_is_not_an_ai Nov 23 '16 at 14:26
  • 1
    @tobi303 You are both totally right; I was merely trying to demonstrate the syntax, not context. I'll update the example. ROFL from Revolver_Ocelot's comment. – Andrew Nov 23 '16 at 14:31
2

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 const Shape, pointer to const Shape) returning bool

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
1

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;
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
0
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.
}
k-messaoudi
  • 347
  • 2
  • 5