user87134: I am new to C++ & I need to call functions of one class from another class. And so that the classes do not know anything about each other. How to do it in Arduino environment?
class Encoder {
  using CallBack2 = void( * )(const int, const int);
  using CallBack0 = void( * )();
  private:
    CallBack2 callbackUpDown;
    CallBack0 callbackTab;
    CallBack0 callbackLongPress;
  public:
    Encoder() {}

  void Setup(CallBack2 updown, CallBack0 tab, CallBack0 cbLongPress) {
    callbackUpDown = updown;
    callbackTab = tab;
    callbackLongPress = cbLongPress;
  }

  void Loop() {
    if (true) {
      callbackUpDown(-1, 300);
      callbackTab();
      callbackLongPress();
    }
  }
};

class Menu {
  public:
    void UpDown(const int direction,
      const int count) {}
      void Tab() {}
};

class RTC {
  public:
    void Setup() {}
    void Toggle() {}
};

class Display {
  public:
    void Toggle() {}
};

Encoder encoder = Encoder();
RTC rtc = RTC();
Menu menu = Menu();
Display display = Display();

void setup() {
  rtc.Setup();
  encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});
}

void loop() {
  encoder.Loop();
}

Output:
In file included from sun.ino:47:0:
callback.h: In function 'void setup()':
callback.h:52:75: error: invalid use of non-static member function 'void Menu::UpDown(int, int)'
   encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle(); rtc.Toggle();});
                                                                           ^
callback.h:28:7: note: declared here
  void UpDown(const int direction, const int count) {}
       ^~~~~~

Thank you!

user35430: What you are doing here
encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});

is not only passing a function pointer. You are passing a member function pointer. This is 2 levels more difficult than function pointers on their own.

The syntax of declaring a member function pointer is different. You need to include the class name in the function pointer declaration. It would look like
using CallBack2 = void( Menu::* )(const int, const int);


When calling a member function pointer, you need an object to call the function on.


Unfortunately, this is so hard that I can't turn your code into a working example. If you want to be able to read your code in 3 months or if you want others to be able to read your code, stick to normal function pointers. They are hard enough.
Suggestion: implement free functions that do what you want:
void menuUpDown(const int dir, const int count)
{
  menu.UpDown(dir, count);
}
void menuTab()
{
  menu.Tab();
}

void setup() {
  rtc.Setup();
  encoder.Setup(menuUpDown, menuTab, []{display.Toggle();rtc.Toggle();});
}

Or, since you're already using lambdas (are you aware of that?), you can also
void setup() {
  rtc.Setup();
  encoder.Setup(
    [](const int dir, const int count){menu.UpDown(dir, count);}, 
    []{menu.Tab();},
    []{display.Toggle();rtc.Toggle();}
  );
}

Note that pupils and students might not have been introduced to the concept of lambdas. If you publish such code online, people might not be able to change it themselves because they don't understand it.

87134: <p>I am new to C++ &amp; I need to call functions of one class from another class. And so that the classes do not know anything about each other. How to do it in Arduino environment?</p>
<pre><code>class Encoder {
  using CallBack2 = void( * )(const int, const int);
  using CallBack0 = void( * )();
  private:
    CallBack2 callbackUpDown;
    CallBack0 callbackTab;
    CallBack0 callbackLongPress;
  public:
    Encoder() {}

  void Setup(CallBack2 updown, CallBack0 tab, CallBack0 cbLongPress) {
    callbackUpDown = updown;
    callbackTab = tab;
    callbackLongPress = cbLongPress;
  }

  void Loop() {
    if (true) {
      callbackUpDown(-1, 300);
      callbackTab();
      callbackLongPress();
    }
  }
};

class Menu {
  public:
    void UpDown(const int direction,
      const int count) {}
      void Tab() {}
};

class RTC {
  public:
    void Setup() {}
    void Toggle() {}
};

class Display {
  public:
    void Toggle() {}
};

Encoder encoder = Encoder();
RTC rtc = RTC();
Menu menu = Menu();
Display display = Display();

void setup() {
  rtc.Setup();
  encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});
}

void loop() {
  encoder.Loop();
}
</code></pre>
<p>Output:</p>
<pre><code>In file included from sun.ino:47:0:
callback.h: In function 'void setup()':
callback.h:52:75: error: invalid use of non-static member function 'void Menu::UpDown(int, int)'
   encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle(); rtc.Toggle();});
                                                                           ^
callback.h:28:7: note: declared here
  void UpDown(const int direction, const int count) {}
       ^~~~~~
</code></pre>
<p>Thank you!</p>
 35430: <p>What you are doing here</p>
<pre class="lang-cpp prettyprint-override"><code>encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});
</code></pre>
<p>is not only passing a function pointer. You are passing a member function pointer. This is 2 levels more difficult than function pointers on their own.</p>
<ol>
<li><p>The syntax of declaring a member function pointer is different. You need to include the class name in the function pointer declaration. It would look like</p>
<pre class="lang-cpp prettyprint-override"><code>using CallBack2 = void( Menu::* )(const int, const int);
</code></pre>
</li>
<li><p>When calling a member function pointer, you need an object to call the function on.</p>
</li>
</ol>
<p>Unfortunately, this is so hard that I can't turn your code into a working example. If you want to be able to read your code in 3 months or if you want others to be able to read your code, stick to normal function pointers. They are hard enough.</p>
<p>Suggestion: implement free functions that do what you want:</p>
<pre class="lang-cpp prettyprint-override"><code>void menuUpDown(const int dir, const int count)
{
  menu.UpDown(dir, count);
}
void menuTab()
{
  menu.Tab();
}

void setup() {
  rtc.Setup();
  encoder.Setup(menuUpDown, menuTab, []{display.Toggle();rtc.Toggle();});
}
</code></pre>
<p>Or, since you're already using lambdas (are you aware of that?), you can also</p>
<pre class="lang-cpp prettyprint-override"><code>void setup() {
  rtc.Setup();
  encoder.Setup(
    [](const int dir, const int count){menu.UpDown(dir, count);}, 
    []{menu.Tab();},
    []{display.Toggle();rtc.Toggle();}
  );
}
</code></pre>
<p>Note that pupils and students might not have been introduced to the concept of lambdas. If you publish such code online, people might not be able to change it themselves because they don't understand it.</p>
