5

これがクラスfooです:

template <typename T>
struct foo
{
    foo()
    {
        t = nullptr;
    }

    foo(T* p, bool flag)
    {
        t = p;
    }
private:
    T* t;
};

クラスバーは次のとおりです。

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

コンストラクターを継承するための正しい構文ですか?「usingfoo::foo;」を使用する場合 その後、Visual C++2010のコンパイラが停止します。では、基本的に、VC ++ 2010のテンプレートクラスからコンストラクターを継承する方法は?

4

4 に答える 4

9
template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo<T>;
};

これを正しく解析するには、templateの前に, を挿入して、テンプレート名と見なす必要があるfoo<T>;ことをコンパイラに伝える必要があります ( は未知であるため、それ自体を調べることはできません)。ただし、using 宣言では using を使用できません。また、名前は のすべてのコンストラクターを参照するわけではありません。代わりに、次のようなコンストラクターの特定のコンストラクター関数テンプレートの特殊化 (はテンプレート引数) を参照します。foofoo<T>T::templatebarT

template<typename T>
foo();

さらに、 using 宣言がtemplate-id(like foo<T>) をその名前として使用することは有効ではありません (これは、関数テンプレートの特殊化を参照することを事実上禁止し、名前変換関数テンプレートの特殊化も禁止することを追加します)。を使用して解析の問題を修正して::templateも (可能であれば)、この時点でまだエラーが発生します。

継承されたコンストラクターが導入されたとき、構文規則を使用してコンストラクターを参照できるようにする特別な規則が追加されました...::...。次に、そのクラスのコンストラクターを 2 つの追加の方法で示すことができます。

  • クラスが template-id (フォームの名前foo<T>) を使用して命名され、最後の部分がテンプレート名と一致する場合 (そう、foo<T>::fooまたはテンプレート テンプレート パラメータである場合) TTP<T>::TTPTTP
  • 最後の部分がクラス名と一致する場合 (so、foo::fooまたはT::TTテンプレート パラメーターである場合)。

これら 2 つの追加の規則は、using 宣言でのみ有効です。そして当然、それらは C++03 には存在しませんでした。C++03 にも存在していたもう 1 つの規則は、次のとおりです。最後の部分が注入されたクラス名を指定する場合、この修飾名もコンストラクターを参照します。

  • foo::fooしたがって、機能します。しかし、このルールだけでは、T::T(ここでTclass を表すfoo) は機能しません。fooというメンバーが存在しないためTです。

したがって、特別なルールを設定すると、次のように書くことができます

using foo<T>::foo;
using bar::foo::foo; // valid too

2 番目も有効です。fooこれは、基本クラスに注入されて にfoo<T>継承された、注入されたクラス名barです。その名前を で参照し、注入されたクラス名を再度参照するbar::foo最後の部分 を追加してfoo、`foo のコンストラクターを示します。

これで、試した最初の名前がコンストラクター関数テンプレートの特殊化を参照する理由がわかりました (それが許可されている場合):foo<T>::fooパーツはすべてのコンストラクターに名前を付け、<T>その後に続く はテンプレートをフィルターで除外し、型を渡すためです。口論。

于 2011-03-23T21:48:17.450 に答える
6

コンパイラがまだコンストラクタの継承をサポートしていないが、可変個引数マクロ、可変個引数テンプレートと右辺値参照、および非常に便利な type_trait をサポートしている場合は、次のような適切な回避策があります。

#include <type_traits>
#include <utility>
#include <ostream>

enum Color {Red, Blue};

#define USING(Derived, Base)                                 \
    template<typename ...Args,                               \
             typename = typename std::enable_if              \
             <                                               \
                std::is_constructible<Base, Args...>::value  \
             >::type>                                        \
    Derived(Args &&...args)                                  \
        : Base(std::forward<Args>(args)...) { }              \


template<typename Mixin>
class add_color
: public Mixin
{
    Color color;

public:
    USING(add_color, Mixin);

    friend std::ostream& operator<<(std::ostream& os, const add_color& x)
    {
        switch (x.color)
        {
        case Red:
            os << "Red";
            break;
        case Blue:
            os << "Blue";
            break;
        }
        os << ' ' << x.first << ' ' << x.second;
        return os;
    }
};

#include <string>
#include <iostream>

int main()
{
    add_color<std::pair<std::string, int>> x1("five", 5);
    std::cout << "x1 = " << x1 << '\n';
    add_color<std::pair<std::string, int>> x3;
    std::cout << "x3 = " << x3 << '\n';
    add_color<std::pair<std::string, int>> x4 = x1;
    std::cout << "x4 = " << x4 << '\n';
    std::pair<std::string, int> p;
    add_color<std::pair<std::string, int>> x5 = p;
    std::cout << "x5 = " << x5 << '\n';
}

is_constructible をまだ持っていない場合、基本的な考え方はそれがなくても機能しますが、「継承されたコンストラクター」は過度に貪欲になります。

于 2011-03-23T21:42:37.063 に答える
3

2 番目のテンプレート パラメーターは必要ありません。

template <typename T>
struct bar: public foo<T>
{
    using foo<T>::foo;
};

すべき

編集私はこれが g++-4.4.1 で動作することを撤回しますが、機能が利用可能になると、これは正しい構文になるはずです

于 2011-03-23T20:32:07.913 に答える
2

他の回答は、C++0x でコンストラクターを継承する方法を説明するのに十分な成果を上げています。ただし、これを書いている時点では、C++0x 機能セット全体を完全に実装しているコンパイラはありません。残念ながら、これは VC++ 2010 がまだコンストラクターの継承をサポートしていないことを意味します。

C++0x 標準はまだ公開されていません。標準の最終草案は3 月中に完成する予定ですが、ISO がそれを公開するにはさらに数か月かかります。その間、コンパイラの作成者は、標準が完成したときに可能な限り C++0x に準拠するように機能を展開しています。

GCC の最新バージョンはコンストラクターの継承をサポートしていると思いますので、今すぐ試してみる必要がある場合は、それを使用できます。もちろん、C++0x のサポートは実験的なものであり、バグが見つかった場合などに変更される可能性があります。

于 2011-03-23T20:35:43.250 に答える