3

次のテスト コードを clang でコンパイルしていました。

template<typename T> struct S1
{
   struct S2{
       enum class E1;
       enum class E2: T;
       enum class E3: short;
    };

    typename S2::E1 b1;
    typename S2::E2 b2;
    typename S2::E3 b3;

    enum class S1::S2::E1 {e11,e12};
    enum class S1::S2::E2 : T {e21,e22};
    enum class S1::S2::E3 : short {e31,e32};
};

template struct S1<int>;

エラーが発生しました: テンプレートの特殊化または定義には、ネストされた型 'S1< T >' に対応するテンプレート パラメーター リストが必要です。私の推測では、構造体 S1 がメンバーの追加中に定義されているためです

enum class S1::S2::E1 {e11,e12} 
enum class S1::S2::E2 : T {e21,e22};
enum class S1::S2::E3 : short {e31,e32};

S1 がまだインスタンス化されておらず、したがって T を解決できないため、コンパイラは T が何であるかを知りません。したがって、コンパイラは列挙型メンバーのサイズを認識しないため、エラーがスローされます。これは正しいです?規格に規定されているか?

注 : gcc はそのようなエラーをスローしません。

4

1 に答える 1

1

そのようなものを定義することは単に許可されていませんenum。n3337 のパラグラフ 7.2/4 は次のように述べています。

enum-keyの後にnested-name-specifierが続く場合、enum - specifierは、nested-name- specifierが参照するクラスまたは名前空間で以前に直接宣言された(つまり、継承も導入もされていない) 列挙を参照するものとします。 using-declarationによって)、enum -specifierは前の宣言を囲む名前空間に現れるものとします。

確かに、エラー メッセージは正確には恒星ではありません。あなたの例は、次のように大幅に単純化できます。

template<typename T> struct S1
{
   struct S2 {
       enum class E;
   };

   enum class S2::E {};
};

同じエラーメッセージが生成されます。

有効なオプションは次のとおりです。

// definition in the scope that the declaration appears in
template<typename T> struct S1
{
   struct S2 {
       enum class E;
       enum class E {};
   };
};

また

// definition in the enclosing namespace scope
template<typename T> struct S1
{
   struct S2 {
       enum class E;
   };
};

template<typename T>
enum class S1<T>::S2::E {};

ネストされたクラスにも同じ規則が適用されます (9.7/3 を参照)。これを試してみると

template<typename T>
struct S1
{
   struct S2 {
       struct S3;
   };

   struct S2::S3 {};
};

次に、GCC も (同様に役に立たない) エラーを生成します。列挙型で同じことをしないのはバグのようです。

そして、あなたがエラーに対して提起した独自の説明は正しくありません。テンプレートの定義では、コンパイラは何が何であるかを知る必要はありません (そして明らかに知ることもできません) T。テンプレートをインスタンス化するときにのみ必要です。他にどのようにtemplate<typename T> struct X { T obj; };機能しますか?

于 2013-09-26T13:03:02.183 に答える