Przekazywanie sparametryzowanej funkcji do metody

0

Witam.
Mam następujący problem:
Chcę przekazać funkcję/metodę z zadaną częścią parametrów do metody, tak aby metoda nie musiała wiedzieć co to jest za typ funkcyjny:
f(x,a,b) -> |podstawiam a=1, b=2| -> fs(x) -> optymalizuj(fs(x))

g(x,c,t,h) -> |podstawiam c=1, t=2, h=3| -> gs(x) -> optymalizuj(gs(x))

Znalazłem coś takiego jak obiekt funkcyjny:
http://wazniak.mimuw.edu.pl/index.php?title=Zaawansowane_CPP/Wyk%C5%82ad_11:_Funktory#Obiekty_funkcyjne

Ale wtedy w optymalizuj będę musiał podać rodzaj obiektu:

 
class Optymalizator{
public:
  double optymalizuj(Sin sin);
  double optymalizuj(Cos cos);
};

I nie będę mógł znaleźć rozwiązania dla nieznanej Optymalizatorowi funkcji matematycznej np. tg().
Może lepiej przekazać funkcję, tylko jak ją wtedy sparametryzować? :

double optymalizuj(double (*funkcja)(double x));
1

Definitywnie potrzebujesz obiektów funkcyjnych, tylko klasa tego obiektu powinna być sparametryzowana liczbą parametrów. Skoro nie znasz obiektów funkcyjnych, to szablonów pewnie też - http://www.cplusplus.com/doc/tutorial/templates/ - szczególnie przedostatni rozdział powinien cię zainteresować.

1

W ten sposób można przekazać funkcję jednoargumentową:

template <typename Tret, typename Targ>
void optymalizuj(Tret (funkcja*)(Targ))
{
    /* ... */
    Tret y = funkcja(x);
    /* ... */
}

/* ... */
optymalizuj(tg);
/* ... */
1

tampates są tu niekoniecznie.

Definiujesz interface:

class UnknownFunction {
public:
     virtual double operator()(double x) const = 0;
}

class Optymalizator{
public:
  double optymalizuj(const UnknownFunction & f);
};

class SinusOmega : public UnknownFunction {
     double omega;
public:
     SinusOmega(double om) : omega(om) {}
     double operator()(double x) const {
         return sin(omega*x);
     }
}

opt->optymalizuj(SinusOmega(3));
opt->optymalizuj(SinusOmega(5));
0

Dziękuję za zainteresowanie! :)
Nie liczyłem na tak szybką reakcję.

Zdążyłem coś skrobnąć bazując na przykładzie od @adf88 :

 
//[EDIT: v2.0]
/* \file
 * \brief Przyklad na klasach
 */
#include <iostream>

using namespace std;

class Potega{
  int wykladnik; 
public:
  double operator()(double x){
   return poteguj(x);
  }
  double poteguj(double x){
   double temp=x;
    for(int i=0; i<wykladnik; i++)
      temp*=x;
    return temp;
  }
  
  void ustaw_wykladnik(int w){ wykladnik=w; }
};

class Optymalizator{
public:
  template <typename KFunk>
  double optymalizuj(KFunk funk); 
};

template <typename KFunk>
double Optymalizator::optymalizuj(KFunk funk){
  return funk(2);
}

double kwadrat(double x){
  return x*x;
}

int main(){
  Optymalizator opt1;
  Potega pot1;

  pot1.ustaw_wykladnik(3);
  cout << "Wynik: " << opt1.optymalizuj(pot1) << endl;
  cout << "Wynik: " << opt1.optymalizuj(kwadrat) << endl;

  return 0;
}

Fajnie wygląda przykład od @MarekR22, niedługo spróbuję.

[EDIT:]
Tak jak wspomniałem spróbowałem i przerobiłem powyższy kod na wersję z dziedziczeniem (wrzucam może komuś się przyda):

 
/* \file
 * \brief Przyklad na klasach
 */
#include <iostream>

using namespace std;

class Potega{
  int wykladnik; 
public:
  double operator()(double x){
   return poteguj(x);
  }
  double poteguj(double x){
   double temp=x;
    for(int i=0; i<wykladnik; i++)
      temp*=x;
    return temp;
  }
  
  void ustaw_wykladnik(int w){ wykladnik=w; }
};

class Optymalizator{
public:
  template <typename KFunk>
  double optymalizuj(KFunk funk); 
};

template <typename KFunk>
double Optymalizator::optymalizuj(KFunk funk){
  return funk(2);
}

double kwadrat(double x){
  return x*x;
}

int main(){
  Optymalizator opt1;
  Potega pot1;

  pot1.ustaw_wykladnik(3);
  cout << "Wynik: " << opt1.optymalizuj(pot1) << endl;
  cout << "Wynik: " << opt1.optymalizuj(kwadrat) << endl;

  return 0;
}

W sumie oba sposoby są fajne.

Jeśli dobrze rozumiem (Z szablonów i dziedziczenia do tej pory nie korzystałem, a z metod wirtualnych rzadko):
Sposób z klasą bazową dla funkcji jest o tyle lepszy że kontroluje się typ przekazywany w argumencie (musi być klasą z przeciążeniem operatora "()").
Natomiast wersja z szablonem ma tę zaletę że mogę podstawić dowolną klasę (nie musi być klasą pochodną), a nawet zwykłą funkcję (dodałem do przykładu funkcję kwadrat).

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.