2008-10-07 15 views
159

Gibt es einen guten Grund, dass ein leerer Satz von runden Klammern (Klammern) nicht gültig ist, um den Standardkonstruktor in C++ aufzurufen?Standardkonstruktor mit leeren Klammern

MyObject object; // ok - default ctor 
MyObject object(blah); // ok 

MyObject object(); // error 

Ich scheine jedes Mal "()" automatisch einzugeben. Gibt es einen guten Grund, dass das nicht erlaubt ist?

+0

Jemand sollte einen besseren Titel dafür finden, aber ich kann nicht denken, was das sein würde. Zumindest "Konstruktor" buchstabieren, um die Suchmaschine (n) zu helfen. –

+1

Und das ist nur ein anderes gutes Beispiel, wo C++ kontextsensitiv ist. Der Beispielcode in der Frage würde auch fehlschlagen, wenn "blah" eine Klasse wäre. – Albert

Antwort

131

drängendsten Parst

Dies bezieht mich auf, was als "C++" s drängendsten Parst" bekannt ist. Grundsätzlich wird alles, was vom Compiler als Deklaration interpretiert werden kann, als Deklaration interpretiert.

Eine andere Instanz desselben Problems:

std::ifstream ifs("file.txt"); 
std::vector<T> v(std::istream_iterator<T>(ifs), std::istream_iterator<T>()); 

v wird als eine Erklärung der Funktion mit 2 Parameter interpretiert.

Die Abhilfe ist ein anderes Paar von Klammern hinzuzufügen:

std::vector<T> v((std::istream_iterator<T>(ifs)), std::istream_iterator<T>()); 

Oder, wenn Sie C++ 11 und list-Initialisierung (auch als einheitliche Initialisierung bekannt) zur Verfügung:

std::vector<T> v{std::istream_iterator<T>{ifs}, std::istream_iterator<T>{}}; 

Damit kann es nicht als Funktionsdeklaration interpretiert werden.

+0

Ich hatte effektive STL gelesen, aber ich erinnere mich nicht daran zu sehen. Ich werde es wieder lesen müssen, danke –

+6

Nitpick: Sie _can_ erklären Funktionen in Funktionen. Es heißt _local functions_ in C und mindestens 'extern" C "foo();' -style ist auch in C++ erlaubt. –

+0

Danke, mmutz, weiß nicht, was ich dachte, als ich es schrieb, wahrscheinlich Konfirmation mit Definition verwechselt. Bearbeitete die Antwort entsprechend. – Constantin

50

Die gleiche Syntax wird für die Funktionsdeklaration verwendet - z. die Funktion object, keine Parameter zu nehmen und MyObject

+1

Danke - es würde mir nicht einfallen, eine Funktion in einem anderen Code zu deklarieren. Aber ich denke, es ist legal. –

10

Rückkehr Da der Compiler denkt, dass es eine Erklärung einer Funktion ist, die keine Argumente und gibt eine Instanz MyObject dauert.

81

Weil es die als Erklärung für eine Funktion behandelt wird:

int MyFunction(); // clearly a function 
MyObject object(); // also a function declaration 
+7

Ich bevorzuge eigentlich die Ausnahme Antwort, es ist viel klarer, was die Ursache des Problems ist – thecoshman

4

Ich denke, würde der Compiler weiß nicht, ob diese Aussage:

MyObject Objekt();

ist ein Konstruktor-Aufruf oder ein Funktionsprototyp eine Funktion namens Objekt mit Rückgabetyp MyObject und keine Parameter zu deklarieren.

4

Wie schon oft erwähnt, ist es eine Deklaration. Es ist so für die Rückwärtskompatibilität. Einer der vielen Bereiche von C++, die wegen ihres Vermächtnisses doof/inkonsistent/schmerzhaft/falsch sind.

7

Sie könnten auch die ausführlichere Konstruktionsweise verwenden:

MyObject object1 = MyObject(); 
MyObject object2 = MyObject(object1); 

In C++ 0x dies ermöglicht auch auto:

auto object1 = MyObject(); 
auto object2 = MyObject(object1); 
+4

Dies erfordert einen Kopierkonstruktor und ist ineffizient – Casebash

+9

@Casebash: Der Compiler ist wahrscheinlich schlau genug, einige 'RVO'-ähnliche Optimierungen zu verwenden, um zu verhindern, dass sie ineffizient sind. – dalle

+1

"Wahrscheinlich" bedeutet "Ich rate".In Bezug auf die Optimierung wollen die Leute normalerweise nicht raten, sondern nehmen den expliziten Weg. – Stefan

2

Von n4296 [dcl.init]:

[Anmerkung:
Da () wird nicht durch die Syntax für Initialisierer erlaubt, X a(); ist nicht die Deklaration eines Objekt der Klasse X, aber die Deklaration einer Funktion kein Argument nehmen und ein X zurückgeben. Die Form() ist in bestimmten anderen Initialisierungskontexten erlaubt (5.3.4, 5.2.3, 12.6.2).
-Ende note]

+2

Können Sie einen Link für die Quelle hinzufügen? –

0

Wie die anderen gesagt, es ist eine Funktionsdeklaration ist. Seit C++ 11 können Sie Klammerinitialisierung verwenden, wenn Sie die leere etwas sehen müssen, die Ihnen explizit sagt, dass ein Standardkonstruktor verwendet wird.

Jedi luke{}; //default constructor