2016-03-14 23 views

Odpowiedz

27

Czy muszę rzucić jakiś sposób?

Tak, można użyć static_cast.

static_cast może być również używany do dwuznaczności przeciążeń funkcyjnych przeprowadzając konwersję funkcja-to-wskaźnik do określonego typu, jak w

std::transform(s.begin(), s.end(), s.begin(), static_cast<int(*)(int)>(std::toupper));

więc można:

auto f1 = static_cast<int(test::*)()>(&test::error); 
auto f2 = static_cast<void(test::*)(int)>(&test::error); 
+29

Drogi panie, to brzydkie. – cat

+2

Za każdym razem, gdy widzę składnię typu C++, mam ochotę napisać coś - cokolwiek - w Haskell. – ApproachingDarknessFish

3

Do rozróżnienia konieczne będzie użycie static_cast. Nie można dokonać oceny

&test::error, ponieważ funkcja jest przeciążona. Fakt, że przypisujesz to do czegoś oznaczonego auto, nie jest natychmiast trafny.

Jedną z poprawek będzie użycie odpowiednio static_cast<int(test::*)()>(&test::error) lub static_cast<void(test::*)(int)>(&test::error).

Wtedy zadziała auto, ponieważ nie będzie niejednoznaczności w odliczeniu typu.

34

Możesz po prostu dokładnie określić typ wskaźnika funkcji członka.

int (test::*f1)() = &test::error; 
void (test::*f2)(int) = &test::error; 
+0

Przepraszamy, mój komentarz był błędny. Plus jeden. – Bathsheba

+2

To; rzutowanie nie jest szczególnie konieczne, ważne jest tylko to, aby kompilator mógł rozróżnić, które przeciążenie powinno być użyte (a więc jakiego typu jest pożądany). –

+0

Dodam, że dodanie typedef sprawiłoby, że rzeczy byłyby jeszcze bardziej czytelne: 'using error_func = int (test :: *)(); error_func f1 = & test :: error; '. – Synxis

1

Ponieważ odpowiedź już jest udzielona, ​​przedstawię rozwiązanie, które jest łatwiejsze dla oczu. Sytuacja ta jest idealna dla makra, jeśli nie chcesz pisać za każdym razem obsada:

template<class T> 
using test_type_t = T test::*; 
#define TEST_CAST(T, F) static_cast<test_type_t<T>>(&F) 

auto f1 = TEST_CAST(void(int), test::error); 
1

Oto rozwiązanie, gdy nie masz internetu, aby przeczytać brzydkie function-pointer-do -menu składnia:

auto err1 = [](test& t) { return t.error(); }; 
auto err2 = [](test& t, int x) { return t.error(x); }; 

Pamiętaj, że do tej pory otrzymujesz zamknięcia jako typy, a nie wskaźniki funkcji. Jeśli potrzebujesz wskaźników funkcyjnych, co jest przydatne, jeśli chcesz przechowywać różne funkcje składowe z tą samą sygnaturą w tablicy, możesz rzucić zamknięcie na wskaźnik (normalnej) funkcji poprzez + (patrz here).

Z tego co widzę w tej chwili, możesz zrobić koncepcyjnie wszystko, co możesz zrobić za pomocą wskaźników funkcji do pojedynczego elementu - z wyjątkiem oczywiście wywoływania rutyny, która dokładnie wymaga takiego wskaźnika. I jest o wiele ładniej.