2010-11-18 6 views
4

Ich kann nicht scheinen, eine extern definierte Variable aus einem Namespace unter Verwendung extern zu verweisen. Es funktioniert vom globalen Gültigkeitsbereich, aber sobald ein Namespace dort hineingeworfen wird, kann es nicht verlinkt werden.C++: Externe Variablen aus einem Namespace verknüpfen

Meine Konstanten Datei wie folgt aussieht:

StringConstants.cpp

#include "MyString.h" 

MyString test1("string1"); 

MyString test2("string2"); 

Das Hauptprogramm sieht wie folgt aus:

main.cpp

#include <stdio.h> 
#include "MyString.h" 

extern MyString test1; 

namespace { 
    extern MyString test2; 
} 

int main(void) { 
    printf("%s\n", test1.Str()); 
    printf("%s\n", test2.Str()); 
} 

Ich bekomme ähnliche Fehler sowohl in der GCC und Visual Studio:

gcc main.o StringConstants.o -o main 
main.o:main.cpp:(.text+0x49): undefined reference to `(anonymous namespace)::test2' 
collect2: ld returned 1 exit status 

1>Linking... 
1>main.obj : error LNK2001: unresolved external symbol "class MyString `anonymous namespace'::test2" ([email protected][email protected]@[email protected]@A) 
1>C:\p4\namespace_repro\namespace_repro2\Debug\namespace_repro2.exe : fatal error LNK1120: 1 unresolved externals 

Ich habe versucht, den Verweis auf test2 (extern MyString ::test2) zu qualifizieren, aber ich denke nur, dass test2 ein statisches Mitglied von MyString ist. Ein benannter Namespace verhält sich nicht anders als ein anonymer Namespace. Aus verschiedenen Gründen möchten wir Namespaces nicht entfernen oder die Externs außerhalb der Namespaces platzieren.

Hier die anderen Dateien, der Vollständigkeit halber:

MyString.h

class MyString { 
public: 
    MyString(const char* str): mStr(str) {}; 
    const char* Str() const { return mStr; } 
private: 
    const char* mStr; 
}; 

Makefile

CC=gcc 
CFLAGS=-Wall 

main: StringConstants.o main.o 

Die Ziele für dieses System sind, dass die Konstanten alle in einer Datei definiert werden, und dass sie werden zur Verbindungszeit aufgelöst, anstatt in einem Header zu sein. Es schien, als ob der obige Code funktionieren würde, aber da er von zwei verschiedenen Linkern abgelehnt wird, scheint mein Verständnis von C++ nicht gut genug zu sein. Ratschläge, wie man dies an die Arbeit bringt, außer die Externes außerhalb der Namespaces zu platzieren?

Antwort

4

$ 7.3.1/2 - "Jeder Name erklärt erste in einem Namespace ein Mitglied dieser Namespace ist."

Dies bedeutet, dass der Name 'test2' Teil des anonymen Namespace ist und in diesem Namespace definiert werden sollte, wenn es verwendet wird.

Es ist kein Problem mit dem anonymen Namespace allein, aber für jeden Namespace.

+0

* seufz * Ich denke, ich kann der Spezifikation nicht widersprechen. Ich habe diesen Abschnitt einige Male angeschaut, aber nicht. t parse die Bedeutung dieser bestimmten Zeile. Danke, dass Sie es geschrieben haben. – breath

5

Was ...

namespace { 
    extern MyString test2; 
} 

... tut, ist zu sagen test2 in einem anonymen Namespace existieren sollte, aber es funktioniert nicht - es im globalen Namespace ist. Sie haben Ihren Compiler angelogen, daher wird ein Objekt erzeugt, das nicht verlinkt wird. Sie benötigen die externe Deklaration aus demselben Namensraumbereich wie die Variable.

ABER, es sollte eine StringConstants.h geben, die main.cpp enthalten sollte, so dass die Übersetzungseinheit die Strings ohne weitere Anweisungen kennt.

+0

+1, der anonyme Namespace ist der Schuldige hier. Beachten Sie, dass er immer noch extern verwenden muss, egal ob in einer Kopfzeile oder nicht. – avakar

+0

Das Problem mit einer StringConstants.h ist, dass es im Grunde erforderlich jede Datei im Programm neu kompilieren muss, wenn jemand eine Konstante ändert oder hinzufügt (was ziemlich üblich sein wird). Gibt es eine Möglichkeit, dem Compiler mitzuteilen, dass ich auf einen globalen Test2 verweisen möchte? – breath

+0

@breath: Wenn die Dinge so volatil sind, wird es nicht viel schlimmer sein, keinen gemeinsamen Header zu haben: Was passiert, wenn jemand erkennt, dass ein Wert von int auf double geändert werden sollte? Programme erstellen und verlinken fortlaufend und scheitern zur Laufzeit. Wenn die freigegebenen Header wirklich zu schwer sind, sollten Sie sie mit separaten Headern für flüchtige Teile aufteilen, die weniger Übersetzungseinheiten benötigen. Betrachten Sie pImpl, Interfaces und andere Abstraktionen, die Clients von der Implementierung entkoppeln. –