Почему мы не можем объявлять псевдонимы пространства имен внутри класса?
Похоже, что невозможно объявить псевдоним пространства имен внутри класса; однако мы можем сделать это на уровне функции (проверено с помощью 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, которые могут быть объявлены внутри класса.
Ответы
Ответ 1
Я не эксперт по стандарту С++, но я выдержу свою шею и пойду, чтобы ответить на ваш вопрос. Я предполагаю, что использование namespace N = A
в объявлении класса не соответствует определению того, как должен определяться член класса.
Стандарт С++ определяет член класса как
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
Важным моментом, заключающимся в =
в объявлении, компилятор ожидает либо инструкции pure-specifier, либо константы-инициализатора, а так как линия не заканчивается нулем, мы не применяем в этом чистом-спецификаторе случай.
Анализируя объявление namespace N = A
, компилятор видит это как
declarator = constant-expression
А поскольку namespace
является ключевым словом, его нельзя использовать.
typedef
разрешен, потому что (из стандарта)
Вложенные типы - это классы и перечисления, определенные в классе, и произвольные типы, объявленные как члены, используя объявление typedef.
Ответ 2
Согласно стандарту С++ 3.3.6
Следующие правила описывают область имен, объявленных в классах.
1) Потенциальная область имени, объявленного в классе, состоит не только из декларативной области, следующей за объявлением имен, но также из всех тел функций, аргументов по умолчанию и конструкторов-инициализаторов конструктора в этом классе (включая такие вещи в вложенные классы)............
Таким образом, вы можете объявлять только вещи из этого списка в классе. Объявление чего-либо еще в области класса недействительно. Не только альянс пространства имен, но и пространство имен. Например
class myClass
{
//compilation error !!!
namespace myNamespace
{
}
using namespace std;//another compilation error
}
Изменить:
Любая идея, почему такое ограничение существует? Это не похоже на typedefs, которые могут быть объявлены внутри класса.
Потому что использование typedefs в классах очень полезно (например, vector<int>::iterator
), а для пространств имен - бесполезно. Рассмотрим следующий код
class myClass
{
namespce N=std;
};
//now let 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
}
Для класса мы можем объявить альянс namespace в файле cpp и НЕТ НЕОБХОДИМО, чтобы daclare его в объявлении класса.
Ответ 3
Я не согласен с тем, что декларация пространства имен внутри класса совершенно бесполезна. Было бы полезно иметь возможность объявлять перечисления в пространствах имен внутри классов. Это позволит вам получить доступ к элементам различных массивов с логическими индексами для конкретного массива.
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]);
}
}