Wie kann ich einen Funktionszeiger mit C ++ 11 mithilfe der Syntax eingeben?

171

Ich würde das gerne schreiben

typedef void (*FunctionPtr)();

mit using. Wie würde ich das machen?

rubenvb
quelle
2
Sehr sicher using, vor allem, weil sich Funktionszeiger- IDs normalerweise in der Mitte einer typedefAnweisung befanden und mit nach vorne verschoben wurden using. Zumindest bin ich dort verloren.
Starturtle

Antworten:

180

Es hat eine ähnliche Syntax, außer dass Sie den Bezeichner aus dem Zeiger entfernen:

using FunctionPtr = void (*)();

Hier ist ein Beispiel

Wenn Sie "die Hässlichkeit wegnehmen" möchten, versuchen Sie, was Xeo vorgeschlagen hat:

#include <type_traits>

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

Und hier ist eine weitere Demo .

0x499602D2
quelle
25
Dang, ich hoffte, es würde die Hässlichkeit :(
beseitigen
10
@rubenvb : using FunctionPtr = AddPointer<void()>;;)
Xeo
2
Es ist möglich, Aliasnamen vom Vorlagentyp zu verwenden, um die Bereinigung fortzusetzenadd_pointer<void()>::type : Verwenden Sie den Vorschlag hier: groups.google.com/a/isocpp.org/d/msg/std-proposals/xDQR3y5uTZ0/…, den Sie schreiben können pointer<function<void>>.
Bames53
5
Diese Typ-Aliase ändern die Typensyntax von obskurer Inside-Out-Syntax zu einer einfachen Syntax von links nach rechts, wodurch benutzerdefinierte Typedefs für bestimmte APIs, die das Schreiben der zusammengesetzten Typen dieser API erleichtern, weitgehend entfallen.
Bames53
10
In C ++ 14 können Sie schreiben: using FunctionPtr = std :: add_pointer_t <void ()>;
Andrzej
46

Die "Hässlichkeit" kann auch beseitigt werden, wenn Sie die Eingabe eines Zeigers vermeiden:

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

http://ideone.com/e1XuYc

Vadim Goryunov
quelle
Dies ist ein interessanter Ansatz, obwohl ich befürchten könnte, den *späteren zu vergessen und verwirrende Fehler zu bekommen.
Apollys unterstützt Monica
Dies ist definitiv die schönste Version, die hier vorgestellt wird. Danke dir. Und ich bevorzuge es, einen Zeiger zu sehen, da es sich schließlich um einen Funktionszeiger handelt.
Pierre
13

Sie möchten eine type-id, die im Wesentlichen genau der Deklaration entspricht, außer dass Sie die löschen declarator-id. Dasdeclarator-id ist normalerweise eine Kennung und der Name, den Sie in der gleichberechtigten Erklärung deklarieren.

Beispielsweise:

int x

Das declarator-idist xso einfach entfernen:

int

Gleichfalls:

int x[10]

Entfernen Sie die x:

int[10]

Für Ihr Beispiel:

void (*FunctionPtr)()

Hier declarator-idist das FunctionPtr. Entfernen Sie es einfach, um Folgendes zu erhalten type-id:

void (*)()

Dies funktioniert, da type-idSie mit a immer eindeutig bestimmen können, wohin der Bezeichner gehen soll, um eine Deklaration zu erstellen. Ab 8.1.1 im Standard:

Es ist möglich, den Ort in der [Typ-ID] eindeutig zu identifizieren, an dem der Bezeichner erscheinen würde, wenn die Konstruktion eine [Deklaration] wäre. Der benannte Typ ist dann der gleiche wie der Typ des hypothetischen Bezeichners.

Andrew Tomazos
quelle
9

Wie wäre es mit dieser Syntax für Klarheit? (Beachten Sie doppelte Klammern)

void func();
using FunctionPtr = decltype((func));
Leo Goodstadt
quelle
1
Was bedeutet die doppelte Klammer in diesem Zusammenhang? Ein Verweis auf einen Funktionszeiger?
0x499602D2
5
Ihr FunctionPtrist kein Funktionszeiger, aber decltype(&f)siehe hier .
Rubenvb
@ 1234597890 FunctionPtr ist eine nicht konstante Wertreferenz auf den Typ 'void ()'
Leo Goodstadt
@rubenvb: Du hast recht. Es ist kein Funktionszeiger, sondern ein Wertverweis auf die Funktion (Typ). Aus diesem Grund schlägt static_assert fehl ... <br/> Versuchen Sie es mit FunctionPtr: using namespace std; #include <iostream> void do_f () {cerr << "what? \ n"; } void f (); using FunctionPtr = decltype ((f)); using FunctionPtr2 = decltype (& f); // Funktioniert nicht // mit FunctionPtr3 = decltype (f); int main () {FunctionPtr ff = do_f; ff (); FunctionPtr2 ff2 = do_f; ff2 (); }
Leo Goodstadt
1

Ein anderer Ansatz könnte die Verwendung des automatischen Rückgabetyps mit dem nachfolgenden Rückgabetyp verwenden.

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

Dies hat den fraglichen Vorteil, dass man sagen kann, dass etwas eine Funktion ptr ist, wenn der Alias ​​mit "auto (*)" beginnt und nicht durch die Bezeichnernamen verschleiert wird.

Vergleichen Sie

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

mit

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

Haftungsausschluss: Ich habe dies Bean Deanes Vortrag "Easing into Modern C ++" entnommen

Silvester
quelle