Nie chcę powiedzieć, że nie mogę tego zrozumieć, ale nie mogę tego zrozumieć. Przeszukałem go i przeszukano Stack Overflow, a potem wyszedłem pusty.Funkcje członków klasy tworzone za pomocą cech [polityki, faktycznie]
Streszczenie i prawdopodobnie zbyt ogólnikowa forma pytania brzmi: Jak mogę użyć wzorca znaków do utworzenia instancji funkcji?[Aktualizacja: użyłem tutaj niewłaściwego terminu. Powinien to być "polityka", a nie "cechy". Cechy opisują istniejące klasy. Zasady określają klasy syntetyczne.] Pojawiło się pytanie podczas modernizacji zestawu optymalizatorów funkcji wielowymiarowych, które napisałem ponad 10 lat temu.
Wszystkie optymalizatory działają, wybierając prostą ścieżkę w przestrzeni parametrów z dala od bieżącego najlepszego punktu ("aktualizacja"), a następnie znajdując lepszy punkt na tej linii ("wyszukiwanie linii"), a następnie testując dla warunku "done", a jeśli nie, to iterowanie.
Istnieją różne metody przeprowadzania aktualizacji, wyszukiwania linii i możliwe do zrobienia testu i inne rzeczy. Mieszać i łączyć. Różne formuły aktualizacji wymagają różnych danych zmiennych stanu. Na przykład aktualizacja LMQN wymaga wektora, a aktualizacja BFGS wymaga macierzy. Jeśli ocenianie gradientów jest tanie, wyszukiwanie linii powinno to zrobić. Jeśli nie, powinien korzystać tylko z ocen funkcji. Niektóre metody wymagają dokładniejszych wyszukiwań linii niż inne. To tylko kilka przykładów.
Oryginalna wersja tworzy kilka kombinacji za pomocą funkcji wirtualnych. Niektóre cechy są wybierane przez ustawienie bitów trybu testowanych w czasie wykonywania. Fuj. Byłoby trywialne definiowanie cech za pomocą # define i funkcji składowych za pomocą # ifdef i makr. Ale tak było dwadzieścia lat temu. Wpadło mi w głowę, że nie potrafię wymyślić nowoczesnego sposobu bzika.
Gdyby była tylko jedna cecha, która byłaby różna, mógłbym użyć ciekawego powtarzającego się wzorca szablonu . Ale nie widzę sposobu, aby rozszerzyć to na dowolne kombinacje cech.
Próbowałem to zrobić przy użyciu boost::enable_if
itp. Wyspecjalizowane informacje o stanie były łatwe. Udało mi się wykonać funkcje, ale tylko poprzez użycie zewnętrznych funkcji, które nie są przyjaciółmi, które mają parametr this
-pointer. Nigdy nawet nie doszedłem do tego, jak sprawić, by funkcje były przyjacielskie, a tym bardziej funkcje członków. Kompilator (VC++ 2008) zawsze skarżył się, że rzeczy nie pasują. Krzyczałem: "SFINAE, ty głupku!" ale kretynem jest prawdopodobnie ja.
Być może kluczowa jest wysyłka tagów. Nie wpadłem w to bardzo głęboko.
Z pewnością jest to możliwe, prawda? Jeśli tak, jaka jest najlepsza praktyka?
AKTUALIZACJA: Oto kolejna próba wyjaśnienia tego. Chcę, aby użytkownik mógł wypełnić zlecenie (manifest) niestandardowego optymalizatora, coś w rodzaju zamawiania z chińskiego menu - jednego z kolumny A, jednego z kolumny B, itp. Kelner, z kolumny A (aktualizatory) , Poproszę aktualizację BFGS o sos z dekompozycji Cholesky'ego. Z kolumny B (szukacze lini), będę mieć interpolację sześciennych linii wyszukiwania z eta 0,4 i rho z 1e-4, proszę. Itd ...
AKTUALIZACJA: OK, okej. Oto gra, którą wykonałem. Oferuję to niechętnie, ponieważ podejrzewam, że to podejście całkowicie błędne. Działa poprawnie pod vC++ 2008.
#include <boost/utility.hpp>
#include <boost/type_traits/integral_constant.hpp>
namespace dj {
struct CBFGS {
void bar() {printf("CBFGS::bar %d\n", data);}
CBFGS(): data(1234){}
int data;
};
template<class T>
struct is_CBFGS: boost::false_type{};
template<>
struct is_CBFGS<CBFGS>: boost::true_type{};
struct LMQN {LMQN(): data(54.321){}
void bar() {printf("LMQN::bar %lf\n", data);}
double data;
};
template<class T>
struct is_LMQN: boost::false_type{};
template<>
struct is_LMQN<LMQN> : boost::true_type{};
// "Order form"
struct default_optimizer_traits {
typedef CBFGS update_type; // Selection from column A - updaters
};
template<class traits> class Optimizer;
template<class traits>
void foo(typename boost::enable_if<is_LMQN<typename traits::update_type>,
Optimizer<traits> >::type& self)
{
printf(" LMQN %lf\n", self.data);
}
template<class traits>
void foo(typename boost::enable_if<is_CBFGS<typename traits::update_type>,
Optimizer<traits> >::type& self)
{
printf("CBFGS %d\n", self.data);
}
template<class traits = default_optimizer_traits>
class Optimizer{
friend typename traits::update_type;
//friend void dj::foo<traits>(typename Optimizer<traits> & self); // How?
public:
//void foo(void); // How???
void foo() {
dj::foo<traits>(*this);
}
void bar() {
data.bar();
}
//protected: // How?
typedef typename traits::update_type update_type;
update_type data;
};
} // namespace dj
int main() {
dj::Optimizer<> opt;
opt.foo();
opt.bar();
std::getchar();
return 0;
}
Czy możesz pokazać przykład tego, co robisz teraz w pseudo-kodzie? –
@Chris Kaminski: 10-letni kod lub eksperymenty? Te ostatnie, jak sądzę. –
Oba być może? Mam na myśli wiele przykładów w STL i zwiększenie wykorzystania funkcji działających na kolekcjach, np. Map/reduce. –