5

Alright, I think the title is sufficiently descriptive (yet confusing, sorry).

I'm reading this library: Timer1.

In the header file there is a public member pointer to a function as follows:

class TimerOne
{
  public:
  void (*isrCallback)();  // C-style ptr to `void(void)` function
};

There exists an instantiated object of the TimerOne class, called "Timer1".

Timer1 calls the function as follows:

Timer1.isrCallback();

How is this correct? I am familiar with calling functions via function pointers by using the dereference operator.

Ex:

(*myFunc)();

So I would have expected the above call via the object to be something more like:

(*Timer1.isrCallback)();

So, what are the acceptable options for calling functions via function pointers, as both stand-alone function pointers and members of an object?

See also:

  1. [very useful!] Typedef function pointer?

Summary of the answer:

These are all valid and fine ways to call a function pointer:

myFuncPtr();
(*myFuncPtr)();
(**myFuncPtr)();
(***myFuncPtr)();
// etc.
(**********************************f)(); // also valid
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • A function pointer, that happens to be a class member, is still a function pointer. Why should the rules be any different? – IInspectable Aug 07 '15 at 03:16

3 Answers3

5

Things you can do with a function pointer.

1: The first is calling the function via explicit dereference:

int myfunc(int n)
{
}

int (*myfptr)(int) = myfunc; 

(*myfptr)(nValue); // call function myfunc(nValue) through myfptr.

2: The second way is via implicit dereference:

int myfunc(int n)
{
}

int (*myfptr)(int) = myfunc;

myfptr(nValue); // call function myfunc(nValue) through myfptr.

As you can see, the implicit dereference method looks just like a normal function call -- which is what you’d expect, since function are simply implicitly convertible to function pointers!!

In your code:

void foo()
{
    cout << "hi" << endl;
}

class TimerOne
{
public:

    void(*isrCallback)();
};


int main()
{

    TimerOne Timer1;
    Timer1.isrCallback = &foo;   //Assigning the address
    //Timer1.isrCallback = foo;   //We could use this statement as well, it simply proves function are simply implicitly convertible to function pointers. Just like arrays decay to pointer.
    Timer1.isrCallback();         //Implicit dereference
    (*Timer1.isrCallback)();      //Explicit dereference
        return 0;
}
Nishant
  • 1,635
  • 1
  • 11
  • 24
  • Thanks! Can you add the examples through the object too please, just to make sure I have clarity on where parenthesis go? ex: Timer1.isrCallback(). <--rewrite with the other option. – Gabriel Staples Aug 07 '15 at 03:12
  • Since it looks like you may have missed it: your code comments didn't quite make it into the code blocks. – jaggedSpire Aug 07 '15 at 03:12
  • @Nishant, thanks! What would this mean exactly, then? Timer1.*isrCallback(); – Gabriel Staples Aug 07 '15 at 03:42
  • Nothing!!!! This will lead you to an error. Do you have any member in your class by name of "*isrCallback"? NO, you have a function pointer named as "isrcallBack"... Hope you got my point – Nishant Aug 07 '15 at 03:49
  • 1
    @GabrielStaples, It dereferences the result of `isrCallback`, as shown [here](http://coliru.stacked-crooked.com/a/ce7d73a651525f25). – chris Aug 07 '15 at 03:51
  • 2
    @Nishant, Function names are not pointers to functions the same way array names are not pointers. This is illustrated [here](http://coliru.stacked-crooked.com/a/08621fb5f8c4e1d3). Functions are simply implicitly convertible to function pointers. – chris Aug 07 '15 at 03:54
  • @chris Yes i know, i made this statement for better understanding... i will update my answer. – Nishant Aug 07 '15 at 03:57
  • @Nishant, thanks for taking the time to write a detailed answer. You covered all the bases, including implicit vs explicit, member vs nonmember, and explicit address assignment (with &) vs implicit address assignment. Those were all things I wanted clarity on. I marked it as the accepted answer last night. – Gabriel Staples Aug 07 '15 at 18:43
4

You don't have to dereference a function pointer to call it. According to the standard ([expr.call]/1),

The postfix expression shall have function type or pointer to function type.

So (*myFunc)() is valid, and so is myFunc(). In fact, (**myFunc)() is valid too, and you can dereference as many times as you want (can you figure out why?)

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Brian, I just read about you on Quora the other day (http://www.quora.com/Brian-Bi-1). I didn't expect an answer from you. OK...can I figure out why? Perhaps because a function itself is a pointer, and you can't dereference a pointer beyond its outermost level?...not sure. – Gabriel Staples Aug 07 '15 at 03:29
  • Can I figure out why? Because the compiler was designed that way. It treats a function the same as a pointer to a function which is the same as a pointer to a pointer to a function, apparently. The compiler is programmed to treat functions as addresses in memory. I don't know, what's the answer why? I'd like to hear your answer. I'm sure you can provide more insight. – Gabriel Staples May 17 '21 at 18:01
  • 1
    @GabrielStaples A function is converted to a function pointer whenever it appears in a context where such conversion is required. So if you dereference a function pointer to get a function, you can always dereference it a second time: the `*` operator requires a pointer, so the function just gets converted back to a function pointer. This can be done as many times as you want. – Brian Bi May 17 '21 at 18:24
2

You asked:

Timer1 calls the function as follows:

Timer1.isrCallback();

How is this correct?

The type of Timer1.isrCallback is void (*)(). It is a pointer to a function. That's why you can use that syntax.

It is similar to using:

void foo()
{
}

void test_foo()
{
   void (*fptr)() = foo;
   fptr();
}

You can also use:

void test_foo()
{
   void (*fptr)() = foo;
   (*fptr)();
}

but the first form is equally valid.

Update, in response to comment by OP

Given the posted definition of the class you would use:

(*Timer1.isrCallback)(); 

To use

(Timer1.*isrCallback)(); 

isrCallback has to be defined as a non-member variable of whose type is a pointer to a member variable of TimerOne.

void (TimerOne::*isrCallback)();

Example:

#include <iostream>

class TimerOne
{
  public:
  void foo()
  {
     std::cout << "In TimerOne::foo();\n";
  }
};

int main()
{
   TimerOne Timer1;
   void (TimerOne::*isrCallback)() = &TimerOne::foo;
   (Timer1.*isrCallback)();
}

Output:

In TimerOne::foo();

(Test this code)


If you want to define isrCallbak as a member variable of TimerOne, you'll need to use:

#include <iostream>

class TimerOne
{
  public:
  void (TimerOne::*isrCallback)();
  void foo()
  {
     std::cout << "In TimerOne::foo();\n";
  }
};

int main()
{
   TimerOne Timer1;
   Timer1.isrCallback = &TimerOne::foo;

   // A little complicated syntax.
   (Timer1.*(Timer1.isrCallback))();
}

Output:

In TimerOne::foo();

(Test this code)

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • For doing it through an object, would the latter form look like this: (*Timer1.isrCallback)(); or this Timer1.*isrCallback();? What's the difference? – Gabriel Staples Aug 07 '15 at 03:35