Можно ли создать указатель на функцию с неопределенными параметрами? c++

Есть абстрактный класс в котором реализован шаблон использования метода возвращающего определенное значение, но параметры этого метода разные при различных реализациях класса, можно ли сохранять очередь (хотябы одну переменную) из указателей на функции с неопредленными параметрами в них?

class A {
  int (*func)(?);
  
  void F() {
    func(?)
  }
};

class B : public A {
  int v_func(int ptr) { std::cout << ptr << std::endl; }
  B {
    func = v_func;
  }
}

Ответы (2 шт):

Автор решения: Stanislav Volodarskiy

Нет, нельзя.

А если бы было можно, то как вы вызовете функцию в методе F. Ей нужны параметры. Какие ей нужны параметры знает только сама функция. Но и функция F тоже должна знать параметры. В конце концов параметры - это контракт между вызывающим кодом и вызываемой функцией.

Так вот, функцию F вы уже написали и откомпилировали. Значить контракт зафиксирован и можно вызывать только функции определённого типа.

→ Ссылка
Автор решения: AlexGlebe

Язык Си типизированный язык. Это значит функция должна быть вызвана на один тип.

Есть вариант создания классов, представляющих любые типы аргументов. Создаём абстрактный класс аргументов. Далее любые варианты как родственные классы от абстрактного. Типы аргументов сами функции должны преобразовывать под собственный класс.

Выкладываю два варианта.

// g++ -Wall -Wextra -Wpedantic -std=c++11 absargs.cpp -o absargs
# include <iostream>
class AbsArgs {
public  :
virtual ~ AbsArgs(){}
} ;

class A {
public :
  int (A::*func)(AbsArgs & );
  int F(AbsArgs & arg) {    
    return  (this ->* func ) ( arg ) ;
  }
} ;

class BArgs : public  AbsArgs {
public  :
  int ptr ;
  BArgs(int x):ptr{x}{}
  virtual ~ BArgs(){}
} ;

class CArgs : public  AbsArgs {
public  :
  double number ;
  std :: string name ;
  CArgs(double d,std::string const & s):number{d},name{s}{}
  virtual ~ CArgs(){}
} ;

class B : public A {
public :
  int v_func(AbsArgs & arg) {
    if(typeid(arg) == typeid(BArgs)) {
      std::cout << "B(B) : " << static_cast<BArgs&>(arg).ptr << std::endl;
      ++  static_cast<BArgs&>(arg).ptr  ;
      return static_cast<BArgs&>(arg).ptr ; }
    if(typeid(arg) == typeid(CArgs)) {
      std::cout << "B(C) : "<< static_cast<CArgs&>(arg).number <<
      " " << static_cast<CArgs&>(arg).name <<
      std::endl;
      ++  static_cast<CArgs&>(arg).number ;
      return 0 ; }
    if(typeid(arg) == typeid(AbsArgs)) {
      std::cout << "B(Abs) : no arguments" << std::endl;
      return 0 ; }
    throw ; }
  B() {
    func = static_cast<int (A::*)(AbsArgs & )>(& B::v_func);
  }
} ;

class C : public A {
public :
  int v_func(AbsArgs & arg) {
    if(typeid(arg) == typeid(BArgs)) {
      std::cout << "C(B) : " << static_cast<BArgs&>(arg).ptr << std::endl;
      --  static_cast<BArgs&>(arg).ptr  ;
      return static_cast<BArgs&>(arg).ptr ; }
    if(typeid(arg) == typeid(CArgs)) {
      std::cout << "C(C) : "<< static_cast<CArgs&>(arg).number <<
      " " << static_cast<CArgs&>(arg).name <<
      std::endl;
      --  static_cast<CArgs&>(arg).number ;
      return 0 ; }
    if(typeid(arg) == typeid(AbsArgs)) {
      std::cout << "C(Abs) : no arguments" << std::endl;
      return 0 ; }
    throw ; }
  C() {
    func = static_cast<int (A::*)(AbsArgs & )>(& C::v_func);
  }
} ;

int main (  ) {
  A * a [ 2 ] ;
  a [ 0 ] = new B ;
  a [ 1 ] = new C ;
  AbsArgs aa  ;
  BArgs ba { 7 } ;
  CArgs ca { 3.1 , "name" } ;
  a [ 0 ] -> F ( aa ) ;
  a [ 0 ] -> F ( ba ) ;
  a [ 0 ] -> F ( ca ) ;
  a [ 1 ] -> F ( aa ) ;
  a [ 1 ] -> F ( ba ) ;
  a [ 1 ] -> F ( ca ) ;
  delete a [ 1 ] ;
  delete a [ 0 ] ;
}

проверка :

$ ./absargs 
B(Abs) : no arguments
B(B) : 7
B(C) : 3.1 name
C(Abs) : no arguments
C(B) : 8
C(C) : 4.1 name

Достоинством служит богатые возможности передачи разных аргументов. Ускорение компиляции из-за скрытия типов аргументов. Сами аргументы имеют область видимости после выполнения метода.

Недостаток : в стеке добавляется запись тип аргументов.

→ Ссылка