5

名前空間メンバーは、宣言の名前空間を囲む名前空間で定義できます。

名前付き名前空間のメンバーは、定義されている名前の明示的な修飾 (3.4.3.2) によってその名前空間の外部で定義することもできます。ただし、定義されているエンティティが名前空間で既に宣言されており、その定義が名前空間の宣言ポイントの後にある場合に限ります。宣言の名前空間を囲みます

void f();

namespace N { void ::f() {} }       // illegal for definition

namespace N { void ::f(); }         // what about redeclaration?

クラスは、宣言の名前空間を囲む名前空間で定義できます。

class-head-name に nested-name-specifier が含まれる場合、class-specifier は、nested-name-specifier が参照するクラスまたは名前空間、またはその名前空間のインライン名前空間セット (7.3.1) (つまり、単に using 宣言によって継承または導入されたものではない) であり、class-specifier は、前の宣言を囲む名前空間に現れるものとします。そのような場合、定義のクラスヘッド名のネストされた名前指定子は、decltype 指定子で始まってはなりません。

struct A;

namespace N { struct ::A {}; }      // illegal for definition

namespace N { struct ::A; }         // what about redeclaration?

また、メンバー関数の定義と静的データ メンバーの定義にも同じ規則があります。

私の質問は、元の宣言を囲まない名前空間で再宣言 (定義ではない) が合法かどうかです。

4

1 に答える 1

1

に関してstruct ::A;[dcl.type.elab]/1は宣言を不正な形式にします:

精緻化された型指定子が宣言の唯一の構成要素である場合、明示的な特殊化 (14.7.3)、明示的なインスタンス化 (14.7.2)、または次のいずれかの形式でない限り、宣言は不正な形式です。

  class-key attribute-specifier-seq opt  識別子 ;
  friend class-key ::opt 識別子 ;
  friend class-key ::opt シンプル テンプレート ID ;
  friend クラス キー ネストされた名前指定子識別子 ;
  friend クラス キー ネストされた名前指定子 templateopt シンプル テンプレート ID ;

関数の場合には問題はありません。[dcl.meaning]/1はそれを許可します:

declarator-idが修飾されている場合、 宣言は、修飾子が参照するクラスまたは名前空間 (または、名前空間の場合は、その名前空間のインライン名前空間セットの要素) の以前に宣言されたメンバーを参照する必要があります (7.3 .1)) またはその専門化に; […] [: 修飾子がグローバル::スコープ解決演算子の場合、declarator-idはグローバル名前空間スコープで宣言された名前を参照します。—エンドノート]

ただし、GCC と Clang はどちらも、定義としての再宣言は、囲んでいる名前空間で行う必要があると主張しています。

于 2016-06-18T14:59:58.043 に答える