2016-07-04 7 views
1

Der folgende Codetemporäre Objekte mit variablen Vorlagenargumenten; andere g ++/Klirren ++ Unterschied

struct foo 
{ 
    foo() 
    { } 

    template <typename T0, typename ... Ts> 
     foo (const T0 & t0, const Ts & ... ts) 
     { foo(ts...); } 
}; 

int main() 
{ 
    foo f(1, 2); 

    return 0; 
} 

kompilieren, ohne Probleme mit g++ (4.9.2) und geben den folgenden Fehler

tmp_002-11,14,gcc,clang.cpp:9:16: error: expected ')' 
     { foo(ts...); } 
      ^
tmp_002-11,14,gcc,clang.cpp:9:13: note: to match this '(' 
     { foo(ts...); } 
      ^
tmp_002-11,14,gcc,clang.cpp:9:14: error: redefinition of 'ts' 
      { foo(ts...); } 
      ^
tmp_002-11,14,gcc,clang.cpp:8:42: note: previous definition is here 
     foo (const T0 & t0, const Ts & ... ts) 
             ^
2 errors generated. 

mit clang++ (3.5).

Wie immer meine Frage ist: Wer hat Recht?

--- EDIT ---

Klarstellung: Ich weiß, dass foo(ts...) kein Anruf an einen Delegierten Konstruktor sein kann, aber (ich glaube, das sein kann), um den Aufbau eines temporären foo Objekt (ein anderes foo Objekt).

Aber, wie von vssoftco, was passiert, wenn sizeof...(ts) == 1U?

In diesem Fall foo(ts...); ist eine (Wieder-) Erklärung eine einzelne Variable ts (so, nehme ich an, sollte clang++ richtig sein) oder die variadische Syntax Vermeidung dieses Problems (so, nehme ich an, sollte richtig sein g++)?

Es gibt C++ 11 Standard-Experten, die das klären können?

ps.entschuldigung für mein schlechtes Englisch.

+0

Ich glaube nicht, dass Sie einen Konstruktor aufrufen dürfen, also sollte gcc das auch ablehnen. – vsoftco

+0

@vsoftco - die Idee ist ein temporäres Objekt zu erstellen, aber ... Ich denke, das Problem ist, wenn diese nur ein Argument – max66

+0

Ohh ich sehe, aber ich denke, der Compiler glaubt, Sie haben einen Anruf dort. Ich bin mir allerdings nicht 100% sicher. In jedem Fall sollte die Delegierung des Konstruktors funktionieren: 'foo (const T0 & t0, const T & ... ts): foo (ts ...) {}' – vsoftco

Antwort

2

Dies sieht aus wie ein Clang Bug. Hier ist eine minimale Wiedergabe:

template <typename ... Ts> void foo (Ts ... ts) 
{ 
    int(ts...); 
} 

(es gibt keine noch brauchen, um die Vorlage zu instanziiert).

Gemessen an den Fehlermeldungen interpretiert clang int(ts...); als Deklaration, was nicht sein kann, weil (ts...) kein Deklarator sein kann.

Man könnte fragen: wenn ts ... ein Parameterpack der Größe eins ist, sollte es nicht ähnlich wie ts geparst werden und damit das ganze Konstrukt als Deklaration interpretieren? Die Antwort ist nein.

Es gibt eine syntaktische Ambiguität in der C++ - Grammatik zwischen "declaration" und "expression-statement" -Produktionen. Wenn ein mehrdeutiges Konstrukt als "Deklaration" analysiert werden kann, handelt es sich um eine "Deklaration". int(ts...) kann nicht so geparst werden, weil die Grammatik keine für ein solches Parsen benötigten Produktionen hat. Sobald das Konstrukt als Ausdrucksanweisung klassifiziert wurde, und nicht davor, können wir ts... als Parameterpaket interpretieren und die Größe von ... (ts) berechnen. Wenn das Konstrukt nicht als Ausdruck klassifiziert ist, hat die Größe von ... (ts) überhaupt keine Bedeutung, weil ts ... keine Bedeutung hat, da eine solche Syntax nicht in einer Deklaration enthalten sein kann.

Sobald festgestellt wird, dass int(ts...); eine Ausdruckanweisung und keine Deklaration ist, kann man sie interpretieren und relevante Vorlagen instanziieren und Parameterpakete erweitern. An diesem Punkt ist es zu spät, zurück zu gehen und zu behaupten, dass es die ganze Zeit eine Erklärung war, basierend auf der Tatsache, dass sizeof...(ts) == 1. Das könnte man unmöglich sizeof...(ts) == 1 ableiten, wenn es eine Deklaration wäre (ts wäre dann kein Parameterpack).

Darüber hinaus scheint Clang scheinbar, dass es nicht einmal eine syntaktisch korrekte Deklaration ist. Fakten wie sizeof...(ts) == 1 können nicht aus etwas abgeleitet werden, das nicht syntaktisch korrekt ist.

+0

wirklich interessant, aber wenn Sie die Vorlage instanziieren (Aufruf 'foo (1,2);', durch Beispiel), Sie bekomme einen Fehler von 'g ++' auch – max66

+0

@ max66 es ist eine minimale Demo. Es funktioniert nur, wenn Sie die Vorlage mit einem einzelnen Argument instanziieren. –

+0

Ich sehe, aber ich verstehe nicht, warum g ++ kompilieren Sie Ihre Template-Funktion, aber kompilieren Sie nicht 'void bar (int i) {int (i); } ' – max66

Verwandte Themen