7

g++ 4.2.1 を使用してこのコードをコンパイルします。

struct S { };
template<typename T> struct ST { };

template<typename BaseType>
class ref_count : private BaseType { };

template<typename RefCountType>
class rep_base : public RefCountType { };

class wrap_rep : public rep_base<ref_count<S> > {
  typedef rep_base<ref_count<S> > base_type;      // line 11
};

私は得る:

bug.cpp:1: error: ‘struct S’ is inaccessible
bug.cpp:11: error: within this context

ただし、wrap_rep使用するクラスを変更するとST:

class wrap_rep : public rep_base<ref_count< ST<int> > > {
  typedef rep_base<ref_count< ST<int> > > base_type;
};

それはうまくコンパイルされます。または、元のコードを次のように変更すると:

class wrap_rep : public rep_base<ref_count<S> > {
  typedef rep_base<ref_count< ::S > > base_type;  // now using ::
};

また、正常にコンパイルされます。私には、元のコードはそのままで問題ないようです。これは g++ のバグですか? そうでない場合、なぜテンプレートの使用が機能するのでしょうか? そして、他のケースでは、なぜ::S必要なのですか?

4

3 に答える 3

7

これらのコードは両方とも無効です (最後のコードのみが有効です) が、(準拠していない) コンパイラは 1 つだけを診断します。別の答えが言うように、これは注入されたクラス名を使用します。クラスは、同じクラスを示すSメンバー名を持つと見なされます。S例(最初の例の前の「class」キーワードS::Sは、デフォルトのコンストラクターではなく、注入されたクラス名への参照を強制するために必要であることに注意してください):

class S { };

class S::S object; // creates an S object
class X : S::S::S::S { }; // derives from class S

クラス テンプレートにも注入されたクラス名があります。注入されたクラス名と同様に、派生クラスに継承ST<int>されるため、その注入されたクラス名を使用するため、形式が正しくありませんが、アクセスすることはできません。4.5 未満の GCC を使用している場合、GCC4.5 で導入された変更に関係している可能性があります。

G++ は DR 176 を実装するようになりました。以前は、G++ はテンプレート基本クラスの注入されたクラス名を型名として使用することをサポートしていませんでした。名前のルックアップにより、囲んでいるスコープでテンプレートの宣言が見つかりました。名前を検索すると、名前の後にテンプレート引数リストが続くかどうかに応じて、タイプまたはテンプレートとして使用できる、injected-class-name が見つかります。この変更の結果、以前は受け入れられていた一部のコードの形式が正しくない可能性があります。

  1. プライベートベースからのものであるため、注入されたクラス名にアクセスできません。または
  2. 注入されたクラス名は、テンプレート テンプレート パラメーターの引数として使用できません。

これらのいずれの場合でも、nested-name-specifier を追加して明示的にテンプレートに名前を付けることで、コードを修正できます。最初のものは -fno-access-control で回避できます。2 番目は -pedantic でのみ拒否されます。


注入されたクラス名をもう少し楽しむために、最初に考えられるように、注入されたクラス名は typedef と同等ではないことに注意してください。注入されたクラス名はクラス名ですが、typedef 名として分類されません。つまり、関数、オブジェクト、または列挙子の名前によって隠される可能性があります。

// valid, the data-member hides the injected class name
struct S { int S; };

注入されたクラス名を参照するには、次のように言うことができますclass S::S(同様に、基本クラスのリストでは、型以外の名前は無視されるため、特別な注意は必要ありません)。S::Sメンバー。

于 2010-07-12T07:36:40.237 に答える
3

あなたの構造体は、匿名の typedef があるかのように注入されることを意味するS基本クラスです。wrap_repwrap_rep

typedef で::前に演算子を使用すると、継承元ではなく、グローバル名前空間で使用するようにコンパイラに指示されます。SSS

このリンクを参照してください。

于 2010-07-12T04:11:01.433 に答える
0

元のコードは、「Sun WorkShop 6 update 2 Compilers C++」で正常にコンパイルされました。これは、私のオフィスでアクセスできる唯一のものです。あなたが持っている他のコンパイラで試してみてください。

于 2010-07-12T03:50:57.453 に答える