Jak wpisać wskaźnik funkcji w C ++ 11 przy użyciu składni?

171

Chciałbym to napisać

typedef void (*FunctionPtr)();

za pomocą using. Jak bym to zrobił?

rubenvb
źródło
2
w usingistocie bardzo conf , zwłaszcza, że ​​identyfikatory wskaźników funkcji zwykle znajdowały się w środku typedefinstrukcji i przesuwały się na początek za pomocą using. Przynajmniej tam się zgubiłem.
starturtle

Odpowiedzi:

180

Ma podobną składnię, z tym wyjątkiem, że usuwasz identyfikator ze wskaźnika:

using FunctionPtr = void (*)();

Oto przykład

Jeśli chcesz „zabrać brzydotę”, wypróbuj sugestie Xeo:

#include <type_traits>

using FunctionPtr = std::add_pointer<void()>::type;

A oto kolejne demo .

0x499602D2
źródło
25
Cholera, miałem nadzieję, że :(
usunie
10
@rubenvb:; using FunctionPtr = AddPointer<void()>;)
Xeo
2
Możliwe jest użycie aliasów typów szablonów do dalszego czyszczenia add_pointer<void()>::type: Korzystając z sugestii tutaj: groups.google.com/a/isocpp.org/d/msg/std-proposity/xDQR3y5uTZ0/ ... możesz pisać pointer<function<void>>.
bames53
5
Te aliasy typów zmieniają składnię typu z niejasnej składni wewnętrznej na prostą składnię od lewej do prawej, co w dużej mierze eliminuje potrzebę stosowania niestandardowych definicji typów dla określonych interfejsów API, które ułatwiają pisanie typów złożonych tego interfejsu API.
bames53
10
W C ++ 14 będziesz mógł pisać: używając FunctionPtr = std :: add_pointer_t <void ()>;
Andrzej
46

„Brzydota” może też zostać usunięta, jeśli unikniesz wpisywania wskaźnika:

void f() {}
using Function_t = void();    
Function_t* ptr = f;
ptr();

http://ideone.com/e1XuYc

Vadim Goryunov
źródło
To ciekawe podejście, chociaż mógłbym się martwić, że zapomnę *później i dostanę mylące błędy.
Apollys obsługuje Monikę
To zdecydowanie najładniejsza prezentowana wersja. Dziękuję Ci. I wolę widzieć wskaźnik, ponieważ w końcu jest to wskaźnik funkcji.
Pierre
13

Chcesz plik type-id, który jest w zasadzie dokładnie taki sam jak deklaracja, z wyjątkiem usunięcia pliku declarator-id. declarator-idJest zazwyczaj identyfikator oraz nazwę jesteś deklarując w equivilant deklaracji.

Na przykład:

int x

declarator-idJest xtak po prostu usunąć go:

int

Również:

int x[10]

Usuń x:

int[10]

Na przykład:

void (*FunctionPtr)()

Oto declarator-idjest FunctionPtr. więc po prostu usuń go, aby uzyskać type-id:

void (*)()

To działa, ponieważ biorąc pod uwagę type-id, zawsze możesz jednoznacznie określić, gdzie identyfikator miałby się udać, aby utworzyć deklarację. Od 8.1.1 w standardzie:

Możliwe jest jednoznaczne zidentyfikowanie lokalizacji w [id-typie], w której pojawiłby się identyfikator, gdyby konstrukcja była [deklaracją]. Nazwany typ jest wtedy taki sam jak typ hipotetycznego identyfikatora.

Andrew Tomazos
źródło
9

A co z tą składnią dla jasności? (Uwaga podwójny nawias)

void func();
using FunctionPtr = decltype((func));
Leo Goodstadt
źródło
1
Co w tym kontekście oznacza podwójny nawias? Odniesienie do wskaźnika funkcji?
0x499602D2
5
Your FunctionPtrnie jest wskaźnikiem funkcji, ale decltype(&f)jest, zobacz tutaj .
rubenvb
@ 1234597890 FunctionPtr jest odwołaniem bez stałej lwartości do typu „void ()”
Leo Goodstadt
@rubenvb: Masz rację. Nie jest to wskaźnik funkcji, ale odniesienie l-wartości do funkcji (typu). Z tego powodu static_assert zawodzi ... <br/> Spróbuj użyć FunctionPtr: using namespace std; #include <iostream> void do_f () {cerr << "co? \ n"; } void f (); using FunctionPtr = decltype ((f)); używając FunctionPtr2 = decltype (& f); // Nie działa // używając FunctionPtr3 = decltype (f); int main () {FunctionPtr ff = do_f; ff (); FunctionPtr2 ff2 = do_f; ff2 (); }
Leo Goodstadt
1

Innym podejściem może być użycie typu automatycznego zwracania z końcowym typem powrotu.

using FunctionPtr = auto (*)(int*) -> void;

Ma to sporną zaletę polegającą na tym, że można powiedzieć, że coś jest funkcją ptr, gdy alias zaczyna się od „auto (*)” i nie jest to zaciemniane przez nazwy identyfikatorów.

Porównać

typedef someStructureWithAWeirdName& (FunctionPtr*)(type1*, type2**, type3<type4&>);

z

using FunctionPtr = auto (*)(type1*, type2**, type3<type4&>) -> someStructureWithAWeirdName&;

Uwaga: zaczerpnąłem to z wykładu Beana Deane'a „Easing into Modern C ++”

Silvester
źródło