7

テンプレート化された基本クラスを使用して基本クラスから にアクセスする際に、using冗長性の問題に遭遇しました。my_type以下のコードでは、派生クラスがその基本クラスの を使用しようとしています。

template <typename T>
class Base {
    public:
        using mytype = T;
};

template <typename T>
class Derived : public Base<T>{
    public:
        // using the base's mytype here
        static typename Base<T>::mytype func() { return 0;}
};

ただし、実際には、これは非常に多くの文字であることがわかりました。Base クラスがテンプレート化されていない場合は、<T>または typename は必要ありません (明らかに)。

私の本当の問題では、ベースから派生したクラスが大量にあり、可能であればこれを簡素化したいと考えています。現時点で私が持っているのは、次の例のようなものです。ここではusing、基本クラスから型を取得するために追加を追加しているだけですが、必要のない余分なレイヤーのように感じます.

template <typename T>
class Derived : public Base<T>{
    public:
        using base_type = typename Base<T>::mytype;
        static base_type func() { return 0;}
};

これはばかげた問題のように思えるかもしれませんが、基本クラスが派生クラスで何度もmytype使用されているため、前者の場合はかなり厄介です。読みやすさを維持するテンプレート化されたベースから型を取得する正しい方法はありますか?

4

2 に答える 2

15

これは、実際の解決策がない言語のよく知られた癖です。テンプレートでのルックアップは 2 つの別々のステップで行われます。ルックアップの最初のフェーズでは、インスタンス化の前に非依存の名前がその意味に解決されますが、2 番目のフェーズでは、依存する名前がインスタンス化に解決されます。

2 つのフェーズの分割は、テンプレートがどこでインスタンス化されるかを知らないテンプレート開発者にいくらかの正気を提供するために、言語に組み込まれました。ルックアップの最初のフェーズは、テンプレートが定義された時点で行われ、開発者はまさにその時点で推論できます。ある時点で、テンプレートは引数に依存する操作を実行しますが、テンプレートの引数がまだ固定されていないため、テンプレートが定義されている場所ではそれらを解決できません。これらの名前は依存していると見なされ、ルックアップはテンプレート引数の置換後に第 2 フェーズに延期されるため、ADL が開始されます。

これはあなたの特定の問題にどのように関係していますか? テンプレート以外のベースから継承する場合、開発者はベースが何であるかを修正しており、テンプレート定義の時点で期待どおりにそれを調べることができます。ただし、ベースがテンプレート引数に依存している場合、ベースクラスの定義は、派生したテンプレート定義の場所ではわかりません。特に、型を置換しないと、コンパイラは、この特定の型に特殊化があるかどうかをおそらく知ることができません。これは、最初のフェーズでは、コンパイラがベースについて何も想定できないため、ルックアップでベースを検索できないことを意味します。

ベースで typedef を使用する直接的な方法は、派生テンプレートの開発者が、型が必要であること、および型ベース テンプレートのインスタンス化で定義されることをコンパイラに明示的に伝えることです。ここでの重要なポイントは、コンパイラはベースについて何も知らないということですが、開発者は、このテンプレートの使用が、ベースのインスタンス化がネストされた型を持たなければならないという契約に準拠することを要求できます。開発者はテンプレートの型に自由に制約を追加できますが、コンパイラはそうではありません。

そのための構文は、最初のブロックにあるものです。型を参照するには、型を参照します。これは、インスタンス化に使用されるものはtypename Base<T>::type何でも使用契約が必要であることをコンパイラに伝えます。ユーザーは、ネストされたメンバーが含まれていることを確認する必要があります( ) を入力します。手短に言えば、2 番目のアプローチを選択できます。内部で検出され、それに解決されるローカル typedef を作成します。その場合、最初のフェーズでの通常のルックアップは、ネストされた typedef を検出し、それが依存する名前を参照していると判断し、2 番目のフェーズの完全なルックアップを延期します。TDerivedBase<T>typetypenameDerived

これは、(読みやすさに関して)より良い方法があるかどうかという質問に対する答えではありませんが、なぜこのようになっているのかについて、ある程度の理解が得られることを願っています。言語を設計する際の決定は恣意的ではありませんでした [理想的であるかどうかにかかわらず、最初のフェーズは不要で不要であると考える人もいますが、恣意的ではありませんでした]

于 2013-11-06T16:11:30.953 に答える