Chcę przekazać przeciążoną funkcję do std::for_each()
algorytmu. Na przykład,
class A {
void f(char c);
void f(int i);
void scan(const std::string& s) {
std::for_each(s.begin(), s.end(), f);
}
};
Spodziewałbym się, że kompilator rozwiąże f()
typ iteratora. Najwyraźniej to (GCC 4.1.2) tego nie robi. Jak więc mogę określić, co f()
chcę?
Odpowiedzi:
Możesz użyć,
static_cast<>()
aby określić, któregof
użyć zgodnie z sygnaturą funkcji implikowaną przez typ wskaźnika funkcji:Możesz też to zrobić:
Jeśli
f
jest to funkcja członkowska, musisz użyćmem_fun
lub w swoim przypadku użyć rozwiązania przedstawionego w tym artykule dr Dobba .źródło
f()
członkiem klasy (patrz edytowany przykład powyżej)reinterpret_cast
. Najczęściej widzę używane do tego odlewy w stylu C. Moja reguła jest taka, że rzutowanie wskaźników funkcji jest niebezpieczne i niepotrzebne (jak pokazuje drugi fragment kodu, istnieje niejawna konwersja).std::for_each(s.begin(), s.end(), static_cast<void (A::*)(char)>(&A::f));
Jagnięta na ratunek! (uwaga: wymagany C ++ 11)
Lub używając decltype dla parametru lambda:
Z lambdami polimorficznymi (C ++ 14):
Lub ujednoznacznij, usuwając przeciążenie (działa tylko w przypadku bezpłatnych funkcji):
źródło
mem_fn
ibind
, przy okazji. To również C ++ 11). Ponadto, jeśli chcemy uzyskać naprawdę pedantyczny,[&](char a){ return f(a); }
jest 28 znaków istatic_cast<void (A::*)(char)>(&f)
ma 35 znaków.Dlaczego to nie działa
Byłoby wspaniale, gdyby tak było! Jednak
for_each
jest to szablon funkcji zadeklarowany jako:Odliczenie szablonowe należy wybrać typ
UnaryFunction
w momencie połączenia. Alef
nie ma określonego typu - jest to przeciążona funkcja, istnieje wielef
typów, z których każdy ma inny typ. Obecnie nie ma sposobu,for_each
aby wspomóc proces odliczania według szablonu, określając, czegof
chce, więc odliczenie szablonowe po prostu się nie udaje. Aby odliczenie szablonu zakończyło się sukcesem, musisz wykonać więcej pracy w witrynie wezwania.Ogólne rozwiązanie tego problemu
Wskoczę tutaj kilka lat i C ++ 14 później. Zamiast używać a
static_cast
(co pozwoliłoby na pomyślną dedukcję szablonu przez „naprawienie”, któregof
chcemy użyć, ale wymaga ręcznego rozwiązania problemu z przeciążeniem, aby „naprawić” poprawne), chcemy, aby kompilator działał za nas. Chcemy wywołaćf
kilka argumentów. W najbardziej ogólny sposób jest to:To dużo do pisania, ale tego rodzaju problem pojawia się irytująco często, więc możemy po prostu zawrzeć to w makro (westchnienie):
a potem po prostu go użyj:
Zrobi to dokładnie to, co chcesz, aby zrobił kompilator - wykona rozwiązanie przeciążenia na
f
samej nazwie i po prostu zrób to, co trzeba. Będzie to działać niezależnie od tego, czyf
jest to funkcja wolna, czy funkcja składowa.źródło
Nie odpowiadam na twoje pytanie, ale czy tylko ja znajduję
prostsza i krótsza niż
for_each
alternatywa sugerowana przez in silico w tym przypadku?źródło
Wydaje się, że problemem tutaj nie jest rozwiązanie przeciążenia, ale w rzeczywistości dedukcja parametrów szablonu . Chociaż doskonała odpowiedź od @In silico rozwiąże ogólnie niejednoznaczny problem przeciążenia, wydaje się, że najlepszym rozwiązaniem w przypadku
std::for_each
(lub podobnego) rozwiązania jest jawne określenie parametrów szablonu :źródło
Jeśli nie masz nic przeciwko używaniu C ++ 11, oto sprytny pomocnik, który jest podobny do (ale mniej brzydki) rzutowania statycznego:
(Działa dla funkcji składowych; powinno być oczywiste, jak zmodyfikować go, aby działał dla funkcji wolnostojących, a powinieneś być w stanie zapewnić obie wersje, a kompilator wybierze odpowiednią dla Ciebie.)
Podziękowania dla Miro Knejp za sugestię: zobacz także https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J .
źródło
R
, nie jest to wydedukowane. Nie ma też o tym wzmianki w tej odpowiedzi.R
, zapewniamArgs
.R
iT
są wywnioskowane. To prawda, że odpowiedź można poprawić. (T
Jednak w moim przykładzie nie ma, ponieważ nie jest to wskaźnik do elementu członkowskiego, ponieważ to by nie zadziałałostd::for_each
.)