7

The goal is to have the member variable _AddValue point to the CreateFirstValue function upon class initialization and after the first invocation of AddValue, all future calls to it will invoke CreateAnotherValue.

Previously, I just had a single AddValue function with a conditional check to determine which function to call. However, I feel like that implementation is flawed because that if check will occur every time and it seems like a function pointer would be beneficial here.

An example:

class Foo
{
 private:
  int _value;
  void (*_AddValue)(int value); // Pointer to function member variable

  void CreateFirstValue(int value)
  {
    _value = value;
    _AddValue = &CreateAnotherValue;
  }

  void CreateAnotherValue(int value)
  {
    // This function will create values differently.
    _value = ...;
  }

 public:
  // Constructor
  Foo()
   : _value(0), _AddValue(CreateFirstValue)
  {
  }

  AddValue(int value) // This function is called by the user.
  {
    _AddValue(value);
  }
};

The code above is not the actual code, just an example of what I'm trying to accomplish.

right now I'm getting an error: argument of type void (BTree::)(int) does not match void (*)(int)

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • This code looks right to me, what is your issue? – Hans Z Jun 15 '12 at 19:50
  • The first error says "argument of type void (BTree::)(int) does not match void (*)(int)" I'm assuming I need to use the address-of operator, but when I add that, I get "ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function." –  Jun 15 '12 at 19:52
  • try _AddValue(0) in your cctor, and then within the body, _AddValue = CreateFirstValue. – Hans Z Jun 15 '12 at 19:58
  • @Hans: No can do, there is no decay from function name to pointer-to-member. You need to use the address-of operator, and that requires a qualified name. And works just fine inside the *ctor-initializer-list*. – Ben Voigt Jun 15 '12 at 20:08
  • No need to add "homework" to the title if the question is tagged as such. Edited. – John Dibling Jun 15 '12 at 20:20
  • @fhaddad78 : Please do not edit your question with corrected code -- that just makes things more _confusing_ for future readers, who would wonder how you got that error with correct code. They can see the correct code in the _answers_. – ildjarn Jun 15 '12 at 20:53

2 Answers2

15
&CreateAnotherValue

This syntax is not valid. To create a pointer-to-member, you have to name the class, even from inside other members. Try

&Foo::CreateAnotherValue

In this case you are talking the address of a qualified non-static member function, which is allowed and prevents the error about address of unqualified member function.

Of course, you then need an appropriately typed variable to store the pointer-to-member in, see Bo's answer for the correct declaration. When it comes time to call it, you will need to use the pointer-to-member-dereference operator (either .* or ->*), so say

(this->*_AddValue)(whatever);

The same rule applies to data, if you say &Foo::_value, you get a pointer-to-member of type int Foo::*. But in the data case, the unqualified name is also accepted, but with very different behavior. &_value gives a normal pointer, type int*, which is the address of the specific _value member variable inside the this instance.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thank you for the excellent explanation. I knew I had the general gist of all this right, just implementation was weird for me. Especially because our text book doesn't go into much depth with regards to function pointers. With your explanation and Bo's example, it's not compiling. Thank you! –  Jun 15 '12 at 20:15
  • Comment above should say ...it's now compiling... (= –  Jun 15 '12 at 20:48
7

  void (*_AddValue)(int value); // Pointer to function member variable

This is not really a pointer-to-member, but a pointer to a free function.

You need to make this

void (Foo::*_AddValue)(int value); // Pointer to function member variable
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • @BoPersson With that change, I'm getting "btree.cpp: In constructor BTree::BTree():" "btree.cpp:9:21: error: argument of type void (BTree::)(int) does not match void (BTree::*)(int)" –  Jun 15 '12 at 20:02
  • @fhaddad - You might need to use `&Foo::CreateAnotherValue` to take the address of the member function. That would match the `Foo::*` of the pointer. – Bo Persson Jun 15 '12 at 20:06
  • with your help and Ben's it's not compiling. I knew it was syntax issues. I'm still quite confused on how one understands how all this stuff works. Lots of time when I am reading the compiler errors, I don't understand what they are saying. –  Jun 15 '12 at 20:16
  • Comment above should say ...it's now compiling... (= –  Jun 15 '12 at 20:48