-2

I am quite new to C++, and probably I had naive problems. I know that there are other smilar questions, but are related to (seems to me) a more complex problems than mine. I am trying to make a firmware for Arduino, using C++ and I've hurt myself with the overloading errors.

I have this code define in a cpp file:

void class1::functionA(void)
{
  object2.functionOfClass2(class1::functionB);
}

The class1 is initialized as:

class class1
{
 public:
 void functionA(void);
 void functionB(void);
 private:
}

And in the compilation gives

no matching function for call to 'class2::functionOfClass2(<unresolved overloaded function type>)'

Translating into the practical:

in my code I am using the Wire library inside a member function of the class1 for an Arduino library, where in the example the object2 and class2 are respectively the Wire object of class TwoWire.

I have the need to call the wire library inside a member function of my class1. This solution is a consequence of a previous lessons, in which I learnt that I cannot call a member function of class1 inside a non-member function, because the instantiation of the non-member function cannot be made since the class is not instantiated as an object yet, and the compiler has no clue on how to do this.

But calling the Wire. object inside a member function, I thought that was possible. But thinking better to it, actually, when passing the class1 member function pointer to the Wire function, the compiler cannot know what to pass to wire, and so the following is WRONG:

void class1::functionA(void)
{
  Wire.onRequest(class1::functionB); //wrong
}

where the onRequest accept void (*)(void) functions.

So trying with

void class1::functionA(void)
{
  Wire.onRequest(&class1::functionB); //wrong
}

The error became:

error: no matching function for call to 'TwoWire::onRequest(void (class1::*)())' candidates are: void TwoWire::onRequest(void (*)())

There is a way to make those things work? If I say static and initializer list, am I on the right way with the right keywords?

thexeno
  • 131
  • 1
  • 8
  • 1
    Had to delete my answer. I don't think this is plainly doable. You need to pass `this` of your `class1` instance to `onRequest`, and you just can't do that if it accepts `void (*)()` (no parameters allowed). A well-designed library would instead define `onRequest` as `onRequest(void (*callback)(void*), void* context)` instead, and you would pass `this` as `context`. – Violet Giraffe Oct 16 '16 at 21:26
  • 1
    The only way to do this is if there's only one `class1` instance in your whole application - then you can substitute this instance unconditionally and call `functionB` on it. – Violet Giraffe Oct 16 '16 at 21:27

1 Answers1

2

&class1::functionB is a pointer-to-member-function, not a pointer-to-function. Its type is void (class1::*)(void), not void (*)(void), as expected by the onRequest method. It means that to call this pointer-to-member-function, it is required to have the instance as well (class1*).

If the class1 is a singleton, the easiest way to solve this is probably making functionB a static member or simply a non-member function (not inside any class).

If class1 cannot be assumed singleton, then the library must have a way to pass a context pointer (usually void*) along the pointer-to-function and this context is a parameter of the callback function. You should pass this as the context and a pointer to a wrapper function, like the following:

void wrapper_for_class1_functionB(void* context)
{
    static_cast<class1*>(context)->functionB();
}

void class1::functionA(void)
{
    Wire.onRequest(&wrapper_for_class1_functionB, this);
}
André Sassi
  • 1,076
  • 10
  • 15
  • The goal is not to make it singleton, infact also the data structures are defined in the class. This means that I can't use a non-member function since it contains data handling of structures defined in the class. – thexeno Oct 19 '16 at 19:40
  • I then tried with your suggestion, seems very interesting, but this requires, again, to modify the Wire library to take another argument. In fact, the error that I got is a non matching function. Am I missing something? – thexeno Oct 19 '16 at 19:42
  • And anyway, also the functions in the "functionB()" there are other member functions that need to be called outside the .cpp, so in the main file, when the object is created. – thexeno Oct 19 '16 at 20:02
  • If the library doesn't provide a context argument that is passed back with the callback, then it is impossible for the user code that installed the callback to know in which context the callback is fired, simply because the callback doesn't receive the context. And [`Wire::onRequest`](https://www.arduino.cc/en/Reference/WireOnRequest) doesn't provide it indeed. The best you can do is to save the context (the `this` pointer, in your case) in a global variable and make sure no two instances can wait for the callback simultaneously. – André Sassi Oct 19 '16 at 20:55