Przekazywanie sparametryzowanej funkcji do metody

Przekazywanie sparametryzowanej funkcji do metody
WA
  • Rejestracja:około 13 lat
  • Ostatnio:około 13 lat
  • Postów:2
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:

Kopiuj
 
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ć? :

Kopiuj
double optymalizuj(double (*funkcja)(double x));
edytowany 1x, ostatnio: waterbear
Sasik
  • Rejestracja:ponad 21 lat
  • Ostatnio:ponad 2 lata
  • Postów:350
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ć.


Nadzieja...
adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 12 lat
1

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

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

/* ... */
optymalizuj(tg);
/* ... */
edytowany 1x, ostatnio: adf88
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:5 minut
1

tampates są tu niekoniecznie.

Definiujesz interface:

Kopiuj
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));

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
S3
Tylko w ten sposób ograniczasz się do przekazywania funkcji, która przyjmuje i zwraca double. Wykorzystując szablon mogłaby być to funkcja przyjmująca i zwracająca dowolny typ.
MarekR22
no, ale przecież ot to mu chodziło. Wiem, że szablony są bardziej uniwersalne, mi chodziło tylko o wykazanie, że nie są one konieczne do rozwiązania problemu.
WA
  • Rejestracja:około 13 lat
  • Ostatnio:około 13 lat
  • Postów:2
0

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

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

Kopiuj
 
//[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):

Kopiuj
 
/* \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).

edytowany 4x, ostatnio: waterbear

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.