2011-02-03 14 views
13

Wygląda na to, że nie można zadeklarować aliasu przestrzeni nazw wewnątrz klasy; jednak możemy to zrobić na poziomie funkcji (testowane za pomocą g ++ 4.3.4):Dlaczego nie możemy zadeklarować aliasów nazw w klasie?

namespace A 
{ 
} 

class C 
{ 
    namespace N = A; // error: expected unqualified-id before `namespace' 
}; 

class D 
{ 
    void f(); 
}; 

void D::f() 
{ 
    namespace N = A; // OK 
} 

Każdy pomysł, dlaczego takie ograniczenie istnieje? Nie wydaje się to bardzo zgodne z typedefs, które można zadeklarować w klasie.

+4

+1, nie wiedziałem, że jest to możliwe: 'nazw N = A;' –

+3

@Alexandre Chyba, że ​​chce coś takiego nazw 'A = A1 A2 :: :: :: A3 A4; ' –

+4

btw +1, ponieważ jest to dla mnie nowość :) –

Odpowiedz

5

Nie jestem ekspertem od standardu C++, ale będę trzymać się za szyję i odpowiedzieć na twoje pytanie. Zakładam, że użycie klasy namespace N = A w deklaracji klasy jest sprzeczne z definicją definiowania klasy.

C++ standard definiuje członka klasy jako

member-specification: 
    member-declaration member-specification_opt 
    access-specifier : member-specification_opt 
member-declaration: 
    decl-specifier-seq_opt member-declarator-list_opt ; 
    function-definition ;opt 
    ::opt nested-name-specifier templateopt unqualified-id ; 
    using-declaration 
    static_assert-declaration 
    template-declaration 
member-declarator-list: 
    member-declarator 
    member-declarator-list , member-declarator 
member-declarator: 
    declarator pure-specifier_opt 
    declarator constant-initializer_opt 
    identifier_opt : constant-expression 
pure-specifier: 
    = 0 
constant-initializer: 
    = constant-expression 

Ważnym punktem będąc = w deklaracji, kompilator spodziewa albo czystej specyfikatora lub stałym initializer oświadczenie i jako linia nie kończy w zera nie stosujemy w tym przypadku czystego specyfikatora.

Analizując oświadczenie namespace N = A kompilator widzi to jako

declarator = constant-expression 

A ponieważ namespace jest kluczowe nie mogą być użyte.

typedef jest dopuszczalne, ponieważ (od standardu)

zagnieżdżone typy klas i wyliczenia zdefiniowane w klasie, i arbitralne rodzaje deklarowane jako członkowie przy użyciu deklaracji typedef.

+1

To jest pouczające, ale nie wychowawcze. Dlaczego podjął tę decyzję? właśnie to chcę wiedzieć. Mój zakład jest taki, że oni przepuszczali puszkę robaków spowodowaną przez ADL. –

6

Według C++ standardowy 3.3.6

The następujących zasad opisuje zakres nazw zgłoszonych w klasach.

1) Potencjalny zakres nazwy zadeklarowanej w klasie składa się nie tylko z regionu deklaratywnego następującego po deklaratorze nazwy, ale także wszystkich ciał funkcji, argumentów domyślnych i konstruktorów-inicjalizatorów w tej klasie (w tym takich rzeczy w klasach zagnieżdżonych). ...........

Możesz więc zadeklarować tylko rzeczy z tej listy w zakresie klasy. Zgłaszanie czegokolwiek innego w zakresie klasy jest niepoprawne. Nie tylko sojusz nazw, ale także przestrzeń nazw. Na przykład

class myClass 
{ 
    //compilation error !!! 
    namespace myNamespace 
    { 
    } 
    using namespace std;//another compilation error 
} 

Edit:

Każdy pomysł, dlaczego takie ograniczenie nie istnieje? Nie wydaje się to bardzo zgodne z typedefs, które można zadeklarować w klasie.

Ponieważ używanie typedefs w klasach jest bardzo użyteczne (na przykład vector<int>::iterator), a dla przestrzeni nazw jest bezużyteczne.Rozważmy następujący kod

class myClass 
{ 
    namespce N=std; 
}; 

//now let's use N 
MyClass::N::vector<int> v;//don't you think, that this syntax is horrible, and useless????? 

Dla porównania zobaczyć, co robi w funkcji

void f() 
{ 
    namespace bnu= boost::numeric::ublas; 
    bnu::matrix<int> m;//and now we can use short name bnu 
} 

Dla klasy możemy zadeklarować namespace sojusz w pliku cpp i jest NIE POTRZEBA do daclare go w deklaracji klasy.

+0

Ok nie jest to atak osobisty, ale nie jesteś człowiekiem :) używaj własnego przykładu 'bnu' i zauważ, że teraz możesz użyć' bnu' w argumentach metod 'myClass' które jest bardzo użyteczne, a także wartości zwracanych (w deklaracjach). Także twoje sformułowanie na górze 'tylko rzeczy z tej listy 'nie ma sensu, odnosisz się do regionów deklaratywnych, nie są one użyteczne. MOREOVER, możesz zadeklarować typedefs i wewnętrzne klasy w zakresie klasy. jak również 'using base :: method' i static_assert. Zakazywanie przestrzeni nazw musi mieć inną motywację, która jest poza wszystkim wymienionym na tej stronie. –

3

Nie zgadzam się, że deklaracja przestrzeni nazw w klasie jest całkowicie bezużyteczna. Przydałoby się zadeklarować wyliczenia w przestrzeniach nazw w obrębie klas. To pozwoli ci uzyskać dostęp do elementów różnych tablic z logicznymi indeksami dla konkretnej tablicy.

class myClass 
{ 
    private: 
     namespace TransAndRotIdx { 
      enum { U, V, W, P, Q, R }; }; 
     namespace RotIdx { 
      enum { P, Q, R }; }; 
     double tr[6]; 
     double r[3]; 

    public: 
     double getTranslationMag(void) 
     { 
      using namespace TransAndRotIdx; 
      return sqrt(tr[U]*tr[U]+tr[V]*tr[V]+tr[W]*tr[W]); 
     } 
     double getRotationMag(void) 
     { 
      using namespace RotIdx; 
      return sqrt(tr[P]*tr[P]+tr[Q]*tr[Q]+tr[R]*tr[R]); 
     } 
} 
+0

Tylko dla zapisu, w C++ 11 można to w zasadzie osiągnąć za pomocą 'enum class' (ale bez korzyści z deklaracji' using'). – wjl

Powiązane problemy