Wie definiere ich einen Namensraum, welcher grundsaetzlich direkt auf den globalen Namensraum folgt?
-
pumuckl schrieb:
mysterio schrieb:
wie ich garantieren kann, dass ein von mir definierter Namensraum sich direkt am globalen Namesraum angliedert.
Wie du schon erraten hast, das geht nicht, wenn du nicht drauf achtest dass du immer alle Namensraumklammern schließt bevor du den fraglichen Namensraum deklarierst/definierst.
Schade eigentlich.
pumuckl schrieb:
Die Frage hat sich dadurch ergeben, dass ich mit hilfe von Macros Quelltext erzeuge, welcher in einen bestimmten Namensraum soll.
Das hört sich böse an. Quelltext zu erzeugen mit Makros mag ja noch gehen, wenn man vorsichtig ist, aber man sollte dann nicht unbedingt die Namensraum-Bezeichner mit ins Makro einbauen. Man sollte sowieso nur auf Makros zurückgreifen wenns notwendig ist. Zeig mal was du machst und wie du es machst - und was du damit erreichen willst.
Naje, die Idee war halt den momentanen Namensraum bzw. ueberhaupt einen Namensraum nicht zu verschmutzen mit generierten Sachen, daher sollte dies in einen eigenen Namensraum gehen.
Und heir einfach mal der Code, aber natuerlich gekuerzt, weil soll ja nur das wesentliche zeigen.
struct StructToTest{ typedef int gw; }; #define If_contains_Type_(NAME) \ namespace fam { \ namespace config { \ \ /* forward declaration to locate the generated code */ \ /* and test classes within this namespace */ \ template < typename T > \ class If_contains_Type_##NAME; \ } \ } \ \ /* the generated test class is defined after the closing bracket */ \ /* of the namespace due to the fact that the whole definition is */ \ /* generated with a macro and usually a programmer use a ; at the */ \ /* end of a macro use. But a ; at a closing namespace bracket is */ \ /* forbidden, however at the end of a class definition it is */ \ /* needed. */ \ template < typename T> \ class fam::config::If_contains_Type_##NAME { \ .... \ } //namespace Test { If_contains_Type_(gw); //} int main() { ::fam::config::If_contains_Type_gw<StructToTest> .... ; return 0; }Mit dem vollqualifizierten Namen, wie im main, kann ich ja dann auf die generierte Klasse zugreifen. Wenn aber der auskommentierte code "namespace Test" mit reinkommt, ist der code halt noch mal in diesem Namensraum tiefer drin und der Aufruf im main wird halt so nicht funktionieren. Daher halt die Frage nach dem Deklarieren des Namenraumes. Schoen waere es, wenn man auch mit
class ::fam::config::....das ganze deklarieren koennte.
Gruesse
-
Ich seh den Sinn der Generierung durch das #define nicht so ganz - vermutlich deshalb, weil dein #define und die generierte Klasse den selben Namen haben, was bestenfalls als extrem unschön zu bezeichnen ist. Die meisten Codestyles schreiben #defines komplett in Großbuchstaben, damit sie schneller zu identifizieren sind. (und das sollten sie sein, weil Makros eben kein C++-Code sind und sich völlig anders verhalten.)
Was willst du denn mit dem generierten Code erreichen?
-
Zunaechst haben sie natuerlich nicht den gleichen Namen, dann das Macro ist If_contains_Type_ und die generierte Klasse ist If_contains_Type_NAME, aber egal.
Und es handelt sich dabei um, wie der Name ausdrueckt, eine Klasse die testet, ob in einer Struktur (in meinem Fall Konfigurationsbeschreibungen) ein gewisser Typ (Der Makroparameter) oder halt bei mehrfacher Verwendung des Makros mehrere Typen definiert sind. Wenn dies der Fall ist, kann man davon abhaengig Code erzeugen, denn die generierte Klasse stellt noch mehr zur Verfuegung und kann so
fam::config::If_contains_Type_gw<StructToTest>::ThenElse<Then, Else>::process();benutzt werden. Then und Else sind halt auch Typen, die dann die entsprechenden Aktionen ausfuehren.
Ich kann bei Bedarf auch ein vollstaendige Beispiel posten, aber ich denke, dies ist hier eigentlich nicht wirklich der Gegenstand.
Wichtig ist mir hier, dass alles zur Compilezeit passiert und halt mit anderen Mitteln als den Code mit
#ifndef ... #endifund zu durchziehen, was exterm unuebersichtlich ist. Da ist die Form "ist Typ enthalten, dann ... sonst ..." finde ich einfach zu lesen, was aber sicherlich auch Geschmackssache ist.
Gruesse
-
Ich habe mir jetzt wass ausgedacht, was es unmoeglich macht das Macro in einem nested Namespace einzusetzen.
Ich habe folgendes definiert
namespace fam { namespace config { enum { If_contains_Type_can_only_be_used_in_global_namespace=1}; } }und dann teste ich in der generierten Testklasse mit
BOOST_STATIC_ASSERT(fam::config::If_contains_Type_can_only_be_used_in_global_namespace == 1);dieses generiert einen Compile-Error, falls das Macro innerhalb eines Namensraumes benutzt wird. Wenn es im globalen Namensraum angewendet wird, laeuft alles, so wie es soll. Daher habe ich dem enum auch einen aussagekraeftigen Namen gegeben, um dem Benutzer auch einen Hinweis zu geben, warum etwas nicht funktioniert.
Gruesse
-
Mach doch im static-assert ein ::fam::config..., sonst testet das evtl. wieder nicht den gewünschten namespace

-
Was Du vorschlaegst, ist im Grunde das Selbe. Es haengt halt davon ab, wo ich das enum definiere.
Aber, wenn ich es mit dem Macro generiere, hast Du natuerlich Recht und ich muss mit :: testen, hat aber den Nachteil, dass ich dann das Macro nur einmal nehmen kann, da sonst diese Definition doppelt vorkommt.
Deshalb habe ich mich dafuer entschieden, diese Definition nicht durch das Macro zu erzeugen, sondern habe sie gesondert geschrieben und so direkt unterhalb des globalen Namespaces gepackt. Der Test ist dann nur im Macro und dies muss man dann halt ohne die :: aufrufen, ansonsten greift man ja immer auf den richtigen Namensraum mit der Definition zu, egal ob man innerhalb eines geschachtelten Namensraumes ist und der Test wird immer war liefern, unabhaengig ob geschachtelter Namensraum oder nicht. Wenn man jedoch die :: weglaesst und das Macro nicht im globalen Namensraum anwendet, so kann er auf die enum-Definition nicht zugreifen und der Code kann durch den Compiler nicht verarbeitet werden. Dies ist der Grund, warum dort halt kein :: stehen darf, weil es sonst nicht funktionieren wuerde.
Gruss
-
Der Test ist dann nur im Macro und dies muss man dann halt ohne die :: aufrufen, ansonsten greift man ja immer auf den richtigen Namensraum mit der Definition zu, egal ob man innerhalb eines geschachtelten Namensraumes ist und der Test wird immer war liefern, unabhaengig ob geschachtelter Namensraum oder nicht.
Genau umgekehrt!
Wenn du :
im Test verwendest, dann ist sichergestellt, dass der Test immer auf [root]:
testet, und nicht auf [current-namespace]:
:b.Wenn du dagegen nur a::b schreibst, dann guckt er bloss ob er das *irgendwo* finden kann. Also ob's ausgehend von irgendeinem der offenen oder mit using reingezogenen Namespaces erreichbar ist.
namespace X { namespace A { namespace B { typedef int TYPE; } // X::A::B } // X::A namespace Y { A::B::TYPE i = 0; // findet X::A::B ::A::B::TYPE j = 0; // fehler } // X::Y } // XOder hab' ich da jetzt irgendwas falsch verstanden?
-
Du bist da nicht ganz verkehrt, wenn ich den folgenden Code
namespace fam { namespace config { enum { If_contains_Type_can_only_be_used_in_global_namespace=1}; } }per Macro erzeuge, dann kann ich mein Makro auch nur einmal in einem Namensraum (dem globalen) anwenden. Deshalb diese Codesequenz direkt definiert.
Dann kann ich den Test vom Macro generieren lassen und abhaengig davon, wo das Macro dann benutzt wird, gibt es einen Fehler oder nicht.
BOOST_STATIC_ASSERT(fam::config::If_contains_Type_can_only_be_used_in_global_namespace == 1); // Kein Fehler namespace X { BOOST_STATIC_ASSERT(fam::config::If_contains_Type_can_only_be_used_in_global_namespace == 1); // Fehler }Gruss
-
Ah, jetzt verstehe ich was du machen willst. Geht aber so nicht

Er findet die Klasse nämlich trotzdem. Probier es aus (dein Beispielcode compiliert ohne Fehler!).Es geht aber, indem man sich zunutze macht, dass man forward declarations beliebig oft wiederholen darf.
Wenn ich im globalen Namespace "class X;" schreibe, und die Klasse ::X schon definiert ist, dann hat das keinen Effekt. Wenn ich aber in Namespace ::FOO "class X;" schreibe, dann ist das eine forward declaration für einen neue Klasse "::FOO::X". Wenn ich die aber nirgends definiere, kann ich darüber einen Fehler erzeugen:
class IF_CONTAINS_TYPE_must_be_used_in_the_global_namespace {}; // we use a fwd. decl here, which is fine if repeated in the global namespace. // if the macro is used in another namespace however, it declares a new class that's not defined anywhere. // we then generate an error by taking it's size. (BOOST_STATIC_ASSERT is only used for convenience, because // it takes care of generating a unique name, and deals with some compiler-bugs/limits) #define IF_CONTAINS_TYPE(X) \ class IF_CONTAINS_TYPE_must_be_used_in_the_global_namespace; \ BOOST_STATIC_ASSERT(sizeof(IF_CONTAINS_TYPE_must_be_used_in_the_global_namespace) >= 0); \ /* ... */ \ // end IF_CONTAINS_TYPE IF_CONTAINS_TYPE(int) // fine IF_CONTAINS_TYPE(bool) // fine namespace Foo { IF_CONTAINS_TYPE(int) // error C2027: use of undefined type 'Foo::IF_CONTAINS_TYPE_must_be_used_in_the_global_namespace' } // namespace FooWas hälste davon?

-
Du hast Recht. Es kompiliert, aber da frage ich mich jetzt, warum es gestern nicht kompiliert hat. Habe jetzt deshalb sowas ????? im Kopf, aber sei es drum.
Deinen Vorschlag finde ich gut und funktioniert prima.
Danke und Gruesse