[1] Funkcja z parametrem jako referencja -- po chwili googlania: http://stackoverflow.com/questions/5349973/why-did-it-compile-errorly-when-i-added-a-reference-argument-to-a-member-functio -- tutaj czytamy:
The problem is that internally, mem_fun tries to set as its argument type a const reference to the argument type of the member function. If you make then function take in a reference, then it tries to create a reference to a reference, which is illegal in C++.
Czyli nie da się poprzez mem_fun()
ani mem_fun_ref()
przekazać parametru jako referencji. To samo wewnętrznie robi mem_fun()
, co powoduje próbę stworzenia referencji do referencji, co jest zabronione.
[2] Działanie funktorów, bindowania, etc: popatrz na to tak. Masz wskaźnik na metodę klasy (w Twoim przypadku caller::funkcja(int)
). Metody są związane z obiektem, nie z klasą, dlatego potrzebny jest kontekst jej wywołania. Wobec tego:
Kopiuj
void A::foo(T1, T2, ...) -> void F(T1, T2, ...)
Robimy mem_fun():
mem_fun(&A::foo) -> void F(caller*, T1, T2, ...)
Jak widać. mem_fun()
dodaje na pierwszej pozycji w liście parametrów wskaźnik do kontekstu wywołania metody, czyli obiektu, na rzecz którego metoda zostanie wywołana.
W przykładach na cplusplus.com pokazane jest, jak używać metod mem_fun()
i mem_fun_ref()
na elementach przechowywanych w kontenerze:
Kopiuj
vector<string> numbers;
vector<int> lengths;
transform(numbers.begin(), numbers.end(), lengths.begin(), mem_fun_ref(&string::length));
Przekazywana jest metoda klasy string
, operuje się też na wektorze string
. W tym wypadku dla każdego elementu w numbers
wywołana zostanie metoda length()
i dopisana do wektora lengths
. Wszystko łatwe i przyjemne.
teraz: po co bind1st()
? Najpierw -- czym jest bindowanie argumentów (właściwie od początku posługujemy się tu terminami związanymi z programowaniem funkcyjnym, warto wiedzieć). Bindowanie ustala jeden z argumentów funkcji na jakąś stałą wartość, powodując zmniejszenie liczby parametrów. Kilka przykładów:
Kopiuj
bind1st(void F(int, double, string), 666) -> void F(double, string) // "bind first" -- pierwszy parametr funkcji ustalony na 666, zwracana jest funkcja dwuargumentowa
bind2nd(void F(int, double, string), 6.66) -> void F(int, string) // "bind second" -- drugi parametr funkcji ustalony na 6.66, zwracana jest funkcja dwuargumentowa
bind3rd(void F(int, double, string), "Devil") -> void F(int, double) // "bind third" -- trzeci parametr funkcji ustalony na "Devil", zwracana jest funkcja dwuargumentowa
Jeszcze raz -- po co to? Ano dlatego, że w Twoim przypadku do for_each()
trafia metoda klasy, która nie jest przechowywana w kontenerze. Wobec tego należy nadać jej właściwy kontekst. Tym kontekstem jest wskaźnik na obiekt callera. Jako, że w momencie wywoływania metody container::each()
znajdujemy się w konstruktorze o_caller
, więc bindujemy metodę mem_ref(&caller::funkcja)
z wskaźnikiem na obiekt callera -- czyli this
. W ten sposób do metody container::each()
wysyłamy funkcję jednoargumentową, i for_each()
nie będzie próbował bindować pierwszego parametru na aktualnie przetwarzany obiekt z kontenera.
[3] Różnica między mem_fun()
a mem_fun_ref()
:
Kopiuj
mem_fun(void A::foo(T1, T2, ...)) -> void F(A*, T1, T2, ...)
mem_fun_ref(void A::foo(T1, T2, ...)) -> void F(A&, T1, T2, ...)
Do bindowania "ręcznego", jak w Twoim przypadku, mem_fun_ref()
się nie nadaje z tego samego powodu, z którego nie można przesyłać parametrów przez referencję. Znajduje jednak zastosowanie w funkcjach bibliotecznych, a różnicę w zastosowaniu mem_fun()
i mem_fun_ref()
można zobaczyć na cplusplus.com.