【问题标题】:Why can't we declare namespace aliases inside a class?为什么我们不能在类中声明命名空间别名?
【发布时间】:2011-02-03 09:45:10
【问题描述】:

在类中声明命名空间别名似乎是不可能的;但是我们可以在函数级别这样做(使用 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
}

知道为什么存在这样的限制吗?这似乎与可以在类中声明的 typedef 不太一致。

【问题讨论】:

  • +1,我不知道这是可能的:namespace N = A;
  • @Alexandre 我猜他想要这样的命名空间A = A1::A2::A3::A4;
  • btw +1 因为这对我来说是新的 :)

标签: c++ namespaces


【解决方案1】:

根据 C++ 标准 3.3.6

以下规则描述了类中声明的名称范围。

1) 类中声明的名称的潜在范围不仅包括名称声明符之后的声明区域,还包括该类中的所有函数体、默认参数和构造函数构造函数初始化器(包括嵌套类)。 ......

因此,您只能在类范围内声明此列表中的内容。在类范围内声明其他任何内容都是无效的。不仅是命名空间联盟,还有命名空间。例如

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

编辑:

知道为什么存在这样的限制吗?这似乎与可以在类中声明的 typedef 不太一致。

因为在类中使用 typedef 非常有用(例如 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 文件中声明命名空间联盟,并且在类声明中不需要来声明它。

【讨论】:

  • 好吧,不是人身攻击,但你错了 :) 使用你自己的 bnu 示例并注意现在你可以在 myClass 方法的参数中使用 bnu,这非常有用,因为以及返回值(在声明中)。此外,您在顶部only things from this list 的措辞毫无意义,您指的是声明性区域,它们不可用。此外,您可以在类范围内声明 typedef 和内部类。以及using base::method 和 static_assert。禁止命名空间必须有本页提及的任何内容之外的其他动机。
【解决方案2】:

我不是 C++ 标准方面的专家,但我会尽力回答您的问题。我假设在类声明中使用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 声明声明为成员的任意类型。

【讨论】:

  • 这是信息但不具有教育意义。委员会为什么做出这个决定?这就是我想知道的。我敢打赌是因为他们预见到了由 ADL 引起的一罐蠕虫。
【解决方案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]);
        }
}

【讨论】:

  • 仅作记录,在 C++11 中,您基本上可以使用 enum class 完成此操作(但没有 using 声明的好处)。
猜你喜欢
  • 2012-11-09
  • 2011-06-03
  • 1970-01-01
  • 2015-11-21
  • 2011-12-10
  • 2016-02-23
  • 2018-07-24
  • 1970-01-01
相关资源
最近更新 更多