Pass a generic method as arg of another method inside a class?


Good evening dear Arduino community,

I KNOW IT SOUNDS LIKE A REPEAT OF OTHER POSTS, BUT PLEASE READ BEFORE DISMISSING…

I have a somewhat complex question. I want to understand the following:

-Is it possible to pass a method (generic, means any datatype, any argument) as an argument of another method that resides inside a class?
If so, what is the correct syntax to do so?

I want to create a non-blocking for loop. My idea is to use a if statement with a counter inside, and execute the user method until the if condition is met. That way the loop scan will enter the “wrapper” method inside the class, check the counter and run the user method, then exit and continue. Once the counter is reached, it just bypasses the method altogether. I know there could be more sophisticated ways to do it (protothreading?) but I also want to explore using more standard structures and for that I need to pass a user method to the function (method) inside the class, through the wrapper method.

Furthermore, I understand that the for loop statements (initialization; condition; increment) in c++ accept any datatypes, including weird references with pointers in it. Is it possible to declare any datatype in the arguments of the passing method as well?

For illustrative purposes, let’s say I create class x. I call a method “for” inside the class that is actually an “if” statement with a counter. The implementation would be (something) like this:

x.for(int startVal, condition, endVal, cntStart, userMethod());

class code would look something like this:

.h

#ifndef FOR_H
#define FOR_H

#include <Arduino.h>

class x{

     public:
     
     void FOR(arg for initial counter state, arg for condition, arg for counter endState, bool countPos, void(*)())  //<-- this part with the method still not figured out!

//initial counter state can be a #define 
//arg for condition -> #define 1 for "<", 2 for "<=", 3 for ">"... etc. (could be an enum too)
//End counter state can be a #define 
//bool countPos can be a #define A 1 for condition "i++", #define B 2 for condition "++i"
//usrMethod() declaration with generic args
    };

#endif

.cpp

#include "FOR.h"

void x::FOR(int iVal, int condition, int fVal, bool countPos, void((*)())){

        
          switch(condition)   //selection of condition (<, >, <=, >=, ==, !=)
                   {
                       case 1:  //if-then constructs to sort out values and conditions, method execution and counter update
                                //use millis() method for nonblocking delays if necessary
                                //declaration of return to continue scan each count or flag and goto to signal completion of loop condition
                        
                     
                                     
                       case 2:  condition for minus or equal than
                       case 3:  condition for major than ...
                        *
                        *   
                    }

.ino

#include <FOR.h>
//set corresponding #defines and global vars

setup()

loop(){

x.for(0, <=, 5000, A, *userMethod(*));   //example of an user call to the class "for" loop

*
// more stuff
*
*
}


void usrMethod(int a, int b, String, c, float d...){}     //whatever arguments the user needs to run each scan on the x.FOR class method

As you can see, the function or method that I want to pass as an argument to the class through the wrapper method is not pre-defined.
What I mean by that is that a Y user could want to write a piece of code that he/she needs in order to run a specific task. I need to be able to pass his/her method, along with any argument(s) used by such method, to the class for processing into the non blocking method inside the class with the if statement.

-I understand that methods can be passed as arguments of another function using pointers to reference them. However the part that I’m missing is the syntax/semantics involved into that.
-I also understand that methods can be passed as arguments only if the typedef is void, as the method itself cannot return any value, is this correct?

-The main purpose of this is to provide an interface method for a user that prevents him/her to think about how to tweak a for loop to keep it non-blocking, which is an advantage when the embedded system requires time slicing to minimize the possibility of deadlocks.

Constructive discussion/comments/proposals/guidance is very much welcomed.

Thanks
-EZ

TLDR: you probably want to use a template.

edzamper:
However the part that I’m missing is the syntax/semantics involved into that.

-I also understand that methods can be passed as arguments only if the typedef is void, as the method itself cannot return any value, is this correct?

not sure I understand. sounds like you’re just not sure of the syntax

here’s an example of a function, wrap() used to control the execution of an arbitrary function. In this case the arbitrary function returns void and has no arguments but it could return a value and have a non-void argument

#include <stdio.h>

int varA = 0;
int varB = 0;

void
funcA (void)
{
    varA++;
}


void
funcB (void)
{
    varB++;
}

// -------------------------------------
void
wrap (
    int   cnt,
    void(*func)(void) )
{
    while (cnt--)
        func();
}

// -------------------------------------
int
main ()
{
    wrap (10, funcA);
    wrap (20, funcB);

    printf (" varA %d, varB %d\n", varA, varB);
}

results in

varA 10, varB 20

In “The C Programming Language” Kernighan describes an example with different sorting routines being passed as an argument to a sub-function.

template is for sure the way to go, as long as you can keep everything in .h files.
If someone could give an example with splitted .cpp/.h files, appreciate!

For an optional function call you could use a callback. This works even with parameters. I did this some days ago with the help of this forum:

//callback für klassen
//https://forum.arduino.cc/index.php?topic=681647.0

#include <Streaming.h>

class Test
{
  private:
    using CallBack = byte (*)(int value);
    const byte zusatz;                                                                  
    CallBack funcPtr;

  public:
    Test(): zusatz(0), funcPtr(nullptr) {}

    Test(byte zusatz, CallBack funcPtr): zusatz(zusatz), funcPtr(funcPtr) {}            // Overload

    byte setCallBack(const CallBack funcPtr)
    {
      (*this).funcPtr = funcPtr;
      return 0;
    }

    void tuwas()
    {
      if (funcPtr)
      {
        byte result = 0;
        result = funcPtr(4711);
        Serial.print("n");             // we are in
        Serial.println(result);        // external callback result
      }
    }
};


byte meineCallbackFunktion(int value)
{
  Serial << "CallbackFunktion: " << value << endl;
  return 42;
}

Test t1;
Test t2(24, meineCallbackFunktion);

void setup()
{
  Serial.begin(115200);
  Serial << "Start: " << __FILE__ << endl;
  Serial << "--- "  << endl;

  t1.tuwas();                             // no output
  Serial << "1-- "  << endl;

  t2.tuwas();                             // "CallbackFunktion2: 4711" and "n42"
  Serial << "2-- "  << endl;
}

void loop()
{}

Wow! thank you guys so much for your support. This is top notch information you all are posting here. I'll look carefully through the examples and will try to replicate on my program!

gcjr:
not sure I understand. sounds like you’re just not sure of the syntax

here’s an example of a function, wrap() used to control the execution of an arbitrary function. In this case the arbitrary function returns void and has no arguments but it could return a value and have a non-void argument

#include <stdio.h>

int varA = 0;
int varB = 0;

void
funcA (void)
{
    varA++;
}

void
funcB (void)
{
    varB++;
}

// -------------------------------------
void
wrap (
    int  cnt,
    void(*func)(void) )
{
    while (cnt–)
        func();
}

// -------------------------------------
int
main ()
{
    wrap (10, funcA);
    wrap (20, funcB);

printf (" varA %d, varB %d\n", varA, varB);
}




results in


varA 10, varB 20




In "The C Programming Language" Kernighan describes an example with different sorting routines being passed as an argument to a sub-function.

Hi there. Can you tell me where do you get the “special” names like func in the void(*func)(void) declaration? I’m bit confused, not sure if this is declared here or if it is a special name like the ones used for smart pointers. I’ve seen func, args, param… etc. on other examples but not sure if the are special names and where to look them up.

Thanks
-EZ

nothing special about the name "func", could replace it with tom, dick harry.

in wrap(), func is the name of an argument that is a function pointer