D
D
Denis Kovalev2018-10-29 21:36:17
C++ / C#
Denis Kovalev, 2018-10-29 21:36:17

What is the correct way to pass a function as a C++ parameter?

There is an App class
in the App.cpp file:

void App::setup() {
  bt_rest.function("startManufacturing", startManufacturing);
}

int App::startManufacturing(String command) {
  ...
  return 1;
}

bt_rest.function takes (char * function_name, int (*f)(String))
But the compiler throws invalid use of non-static member function on bt_rest.function("startManufacturing", startManufacturing);
Already tried everything...

Answer the question

In order to leave comments, you need to log in

3 answer(s)
R
Roman, 2018-10-30
@DenKov

if bt_rest is https://github.com/marcoschwartz/aREST/blob/master...
copy is as in original

// Functions array
  uint8_t functions_index;
  int (*functions[NUMBER_FUNCTIONS])(String);
  char * functions_names[NUMBER_FUNCTIONS];

void function(char * function_name, int (*f)(String)){

  functions_names[functions_index] = function_name;
  functions[functions_index] = f;
  functions_index++;
}
Maybe so

при условии что App будет в единственном экземпляре.
#include<iostream>
#include<string>
/*
* Будем считать, что std::string это String
*/
#define NUMBER_FUNCTIONS 10
struct aRest
{
  uint8_t functions_index;
  int (*functions[NUMBER_FUNCTIONS])(std::string);
  char* functions_names[NUMBER_FUNCTIONS];
  //...
  aRest() : functions_index(0){};
  void function(char * function_name, int (*f)(std::string))
  {
    functions_names[functions_index] = function_name;
    functions[functions_index] = f;
    functions_index++;
  }
};

class App
{
  aRest bt_rest;
public:
  explicit App() : bt_rest(){};
  //...
  int startManufacturing(std::string command);
  void setup();
  void call(std::string s);// Для теста. Там то же по другому...
  //...
};

int App::startManufacturing(std::string command)
{
  std::cout << "startManufacturing\n"
            << "with command " << command
            << " " << this << std::endl;
  return 1;
}

void App::setup()
{
  bt_rest.function("startManufacturing", (int(*)(std::string))&startManufacturing);
  //reinterpret_cast<int(*)(std::string)>(&startManufacturing)
}

void App::call(std::string s)
{
  bt_rest.functions[0](s);
}

int main()
{
  App ap;
  ap.setup();
  ap.call("COMMAND");
}
or fork aRest
#include<iostream>
#include<string>
#include<functional>

#define NUMBER_FUNCTIONS 10
template<typename T>
struct aRest
{
  uint8_t functions_index;

  int (T::*functions[NUMBER_FUNCTIONS])(std::string);
  char* functions_names[NUMBER_FUNCTIONS];
  //...
  aRest() : functions_index(0){};

  void function(char * function_name, int(T::*f)(std::string))
  {
    functions_names[functions_index] = function_name;
    functions[functions_index] = f;
    functions_index++;
  }
};

class App
{
  aRest<App> bt_rest;
public:
  App() : bt_rest(){};
  //...
  int startManufacturing(std::string command);
  void setup();
  void call(std::string fn);
  //...
};

int App::startManufacturing(std::string command)
{
  std::cout << "startManufacturing\n"
            << "with command " << command
            << " " << this << " " << std::endl;
  return 1;
}

void App::setup()
{
  bt_rest.function("startManufacturing", &startManufacturing);
}

void App::call(std::string s)
{
  std::mem_fn(bt_rest.functions[0])(this, s);
}

int main()
{
  App ap;

  ap.setup();

  ap.call("COMMAND");
}

M
Mercury13, 2018-10-29
@Mercury13

Don't forget that startManufacturing has a hidden this parameter.
Four options.
1. Use a pointer to the App method:

Rest::function(char * function_name, int (App::* f)(String), App& object)
      // вместо App можно какой-то интерфейс, который App реализует
…
object.*f("string");
...
bt_rest.function("", &App::startManufacturing, *this);

2. Make startManufacturing static:
class App {
  static int startManufacturing(String command)
};

3. Make a wrapper with a closure:
Rest::function(char * function_name, int (*f)(String, void*), void*);

void doStartManufacturing(String command, void* closure) {
  reinterpret_cast<App*>(closure)->startManufacturing(command);
}
...
bt_rest.function("startManufacturing", doStartManufacturing, this);

4. "Avoid unfamiliar women and global variables." Crutch, in general.
App app;
int doStartManufacturing(String command) { return app.startManufacturing(command); }
...
bt_rest.function("startManufacturing", doStartManufacturing);

Oh yes. You are passing Strings by value. Are they adapted to such a transfer, or is it better to follow the link?

G
GavriKos, 2018-10-29
@GavriKos

You can't just take and pass a non-static method. Because it is not clear on which instance to call it.
Either make a static method, or remake bt_rest.function so that it also accepts an instance.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question