2016-03-01 5 views
34

Der folgende Code kompiliert sauber mit GCC:Ist es legal, den vorherigen Funktionsparameter zu verwenden, um einen neuen zu deklarieren?

void func(int arg1, decltype(arg1) arg2) 
{ 
    (void)arg2; 
} 
int main(){} 

ich diesen Befehl zu kompilieren:

g++ -std=c++14 test.cpp -o test -pedantic-errors -Wall -Wextra 

Aber eine solche Verwendung eines Parameters in der Mitte der Funktionsdeklaration seltsam scheint. Ist es tatsächlich in Standard C++ gültig, oder ist es eine GCC-Erweiterung?

+0

Ich gehe davon aus, dass die Art von 'arg1' ist viel komplexer in Ihrem aktuellen Code? Und ohne auf die Spezifikation oder irgendwelche Referenzen zu schauen, aber etwas über Parsing zu wissen, würde ich denken, dass es in Ordnung ist, weil das Parsen von Sprachen wie C++ sehr viel von oben nach unten von links nach rechts ist. Wenn der Compiler die Deklaration für 'arg2' analysiert, muss er bereits die Deklaration von 'arg1' analysiert haben, so dass er definitiv den Typ von 'arg1' kennt. Wenn es wirklich "erlaubt" ist, weiß ich nicht, auch wenn es in die entgegengesetzte Richtung funktioniert (mit 'declltype (arg2)' für 'arg1'). –

+0

@JoachimPileborg natürlich hat der tatsächliche Code viel komplexeren Typ für 'arg1', sonst würde ich sogar daran denken,' declltype' darauf zu verwenden. – Ruslan

+0

FWIW, MSVC++ 2013 und seine Intellisense (EDG) akzeptieren beide ebenfalls. – MSalters

Antwort

20

Das ist in Ordnung. Die ISO C++11 Standard gibt sogar Ihre Situation als Beispiel.

Zunächst wird der Parameter ist in Umfang:

3.3.3 Block-Rahmen [ basic.scope.lokale ]

Die potentielle Anwendungsbereich eines Funktionsparameternamen (ein darunter in einem Lambda-declarator erscheinenden) oder eine Funktion lokale vordefinierte Variable in einer Funktionsdefinition (8.4) beginnt, an seinem Punkt der Erklärung.

8.3.5 Funktionen [ dcl.fct ]

[ Hinweis:

Ein Beispiel ist hier zu finden Diese Transformation hat nicht die Arten der Parameter beeinflussen. Zum Beispiel sind int (*) (const int p, decltype (p) *) und int (*) (int, const int *) identische Typen. - Endnote ]

+0

Haben Sie einen Link? .321 –

+3

@AaronHall Die 'C++ 11' Standaard ist hier verkauft: http://webstore.ansi.org/RecordDetail.aspx?sku=INCITS%2FISO%2FIEC+14882-2012 aber Sie können einen freien Entwurf (nahe identisch?) erhalten, indem Sie nach "n3290.pdf" googlen. Alle Entwürfe bis zum Finale sind frei. – Galik

6

Wenn wir in N3979 suchen [dcl.fct.default] wir haben

Standard Argumente jedes Mal ausgewertet werden die Funktion aufgerufen wird. Die Reihenfolge der Auswertung von Funktionsargumenten ist nicht spezifiziert. Folglich dürfen Parameter einer Funktion in einem Standardargument nicht verwendet werden, auch wenn sie nicht ausgewertet werden. Parameter einer Funktion, die vor einem Standardargument deklariert wurde, befinden sich im Gültigkeitsbereich und können Namespace- und Klassenmembernamen ausblenden. [Beispiel:

int a; 
int f(int a, int b = a);    // error: parameter a 
             // used as default argument 
typedef int I; 
int g(float I, int b = I(2));   // error: parameter I found 
int h(int a, int b = sizeof(a));  // error, parameter a used 
             // in default argument 

[...]

Emphasis Mine

So im Beispiel a bekannt ist, wenn wir b bekommen und es versteckt die a von dem anrufenden Rahmen . Dies führt zu der Annahme, dass jeder Funktionsparameter vor jedem nachfolgenden Parameter bekannt ist. Dies bedeutet, dass Sie seinen Typ verwenden können. Sie können seinen Wert nicht verwenden, da die Reihenfolge der Auswertung der Werte nicht angegeben ist. Die Namen sollten jedoch in der Reihenfolge von links nach rechts eingegeben werden.

+0

Sie sind definitiv im Umfang, aber ist das ausreichend? – MSalters

+0

@MSalter, um sie mit 'declltype' zu ​​verwenden, denke ich. – NathanOliver

10

Ja, es ist legal. Es ist im Grunde nur eine Frage des Umfangs. Aus [basic.scope.block]:

Die potentiellen Anwendungsbereich eines Funktionsparameternamen (einschließlich eines in einem lambda-declarator erscheinenden) oder eine Funktion lokale vordefinierte Variable in einer Funktionsdefinition (8.4) beginnt mit der Deklaration.

Der Umfang der arg1 beginnt hier:

void func(int arg1, decltype(arg1) arg2) 
------------------^ 

Daher arg1 zur Deklaration von arg2 im Gültigkeitsbereich befindet. Ich denke, das reicht.

Die Regel für disallowing arg2-arg1 säumige getrennt ist - was mir schlägt vor, dass arg1 in Umfang und hatte ausdrücklich nicht anerkannt werden.

Verwandte Themen