Почему мы не можем объявить псевдонимы пространства имен внутри класса? - PullRequest
13 голосов
/ 03 февраля 2011

Похоже, невозможно объявить псевдоним пространства имен внутри класса; однако мы можем сделать это на уровне функций (протестировано с g ++ 4.3.4):

namespace A
{
}

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

class D
{
  void f();
};

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

Есть идеи, почему существует такое ограничение? Это не очень согласуется с typedefs, которые могут быть объявлены внутри класса.

Ответы [ 3 ]

6 голосов
/ 03 февраля 2011

Согласно стандарту C ++ 3.3.6

Следующие правила описывают область имен, объявленных в классах.

1) Потенциальная область имени, объявленного в классе, состоит нетолько декларативной области, следующей за декларатором имени, но также всех тел функций, аргументов по умолчанию и конструкторов ctor-инициализаторов в этом классе (включая такие вещи во вложенных классах)............

Таким образом, вы можете объявить только вещи из этого списка в области видимости класса.Объявление чего-либо еще в области видимости недопустимо.Не только альянс пространства имен, но и пространство имен.Например,

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

Редактировать:

Есть идеи, почему существует такое ограничение?Это не очень согласуется с typedefs, который может быть объявлен внутри класса.

Поскольку использование typedefs в классах очень полезно (например, vector<int>::iterator), в то время как для пространств имен это бесполезно.Рассмотрим следующий код

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?????

Для сравнения посмотрите, что он делает в функции

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

Для класса мы можем объявить альянс пространства имен в файле cpp, и есть NO NEED чтобы объявить это в объявлении класса.

5 голосов
/ 03 февраля 2011

Я не эксперт по C ++ Standard, но я выложу свою шею и попробую ответить на ваш вопрос.Я предполагаю, что использование namespace N = A в объявлении класса противоречит определению того, как должен быть определен член класса.

Стандарт C ++ определяет член класса как

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

.Важным моментом, являющимся = в объявлении, компилятор ожидает либо оператор чистого спецификатора, либо оператор константы-инициализатора, и поскольку строка не заканчивается на ноль, в этом случае мы не применяем чистый спецификатор.

Анализируя объявление namespace N = A, компилятор видит это как

declarator = constant-expression

И поскольку namespace является ключевым словом, его нельзя использовать.

typedef разрешено, потому что (из стандарта)

Вложенные типы - это классы и перечисления, определенные в классе, и произвольные типы, объявленные как члены с помощью объявления typedef.

3 голосов
/ 01 февраля 2012

Я не согласен с тем, что объявление пространства имен внутри класса совершенно бесполезно.Было бы полезно иметь возможность объявлять перечисления в пространствах имен внутри классов.Это позволит вам получить доступ к элементам различных массивов с логическими индексами для конкретного массива.

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]);
        }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...