web-dev-qa-db-ja.com

「テンプレート」の派生クラスへの「typedef」の伝播

Typedefのみを含む基本クラスを定義しようとしています。

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
private:
    Vec_t v;  // fails - Vec_t is not recognized
};

BでVec_tが認識されないというエラーを受け取り、明示的に記述する必要があるのはなぜですか?

typename A<T>::Vec_t v;
59
dimba

この質問は重複していると思いますが、今は見つけることができません。 C++標準では、14.6.2/3に従って名前を完全に修飾する必要があるとされています。

クラステンプレートまたはクラステンプレートのメンバーの定義で、クラステンプレートの基本クラスがテンプレートパラメーターに依存している場合、非修飾名のルックアップ中に基本クラススコープは検査されませんクラステンプレートまたはメンバーの定義時点、またはクラステンプレートまたはメンバーのインスタンス化中。

UPD:最終的に重複が見つかりました: ここにあります

44

テンプレートの場合、依存名およびnondependentという名前があります。

名前がテンプレートパラメータTに依存する場合、そのdependent名前と、パラメータTに依存しない他の名前はindependent名前。

ルールは次のとおりです。コンパイラは、非依存名(Vec_tなど)を検索するときに、依存ベースクラス(Aなど)を検索しません。その結果、コンパイラーは、それらが存在することはもちろんのこと、型であることも知りません。

コンパイラは、Vec_tは、Tを認識するまでは型です。なぜなら、A<T> どこ A<T>:: Vec_tはデータメンバーです

したがって、解決策はtypenameを使用することです

 typename A<T>::Vec_t v;  ← good

このことをお勧めします https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types

古い(壊れた)リンク: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

35
Xinus

コンパイラはVec_tはタイプに名前を付けます。例えば、 A<T>T=intnot特定のtypedefを持ちます。

7
Jesse Beder

完全を期すために、この迷惑を少し軽減する方法を次に示します。

  • 派生クラスでそれらのタイプを再定義するか、メソッドと同様に-
  • using declarationで派生クラススコープにこれらの名前をインポートするだけです。

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A<T>::Vec_t;
    // .........

private:
    Vec_t v;
};

派生クラスで継承されたtypedefについて複数の言及がある場合に役立ちます。また、毎回typenameを追加する必要はありません。

5
Roman Kruglov

コンパイラはVec_tがどこから来たのかわからないため、Vec_tの使用を明示的に修飾する必要があります。

クラステンプレートAは特殊化されている可能性があるため、Aの構造については何も想定できません。特殊化には、typedefではないVec_tが含まれるか、メンバーVec_tがまったく含まれない場合があります。

2
user200783

Vec_tは依存名ではないため、コンパイラはテンプレート(この場合はベースクラス)をインスタンス化せずに、それが何であるかを知る必要があります。本当に違いはありません:

template <class T>
class X
{
    std::string s;
}

ここでも、名前はテンプレート引数Tに依存しないため(コンパイラが想定できる限り)、Xがインスタンス化されていない場合でも、コンパイラはstd :: stringについて知る必要があります。

全体として、テンプレートベースクラスのtypedefは、派生クラスで使用するのはむしろ役に立たないようです。ただし、typedefはユーザーにとっては便利です。

1
UncleBens

この概念は、std::vector<T>の使用方法に関連付けることができます。たとえば、std::vector<int> Fooがある場合。ここで、そのメンバー型のいずれかを使用することにしました。iteratorと言いましょう。このシナリオでは、明示的に言及しています

std::vector<int>::iterator foo_iterator;

同様に、あなたの場合、Vec_ttemplate <typename T> class Aのパブリックメンバタイプを使用するには、次のように明示的に宣言する必要があります。

A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;
1
RAD