3

C++でポリシーベースのデザインパターンを調べているうちに、解決策が見つからないという問題が発生しました。ポリシーベースのクラスのコンストラクタをジェネリックポリシークラス内のメンバ変数を参照することなく、ここポリシーベースのデザインでコンストラクタをコピー/移動する

は例です:上記のコードで

class Foobase { 
public: 
    Foobase(int v) :val(v) { } 
protected: 
    int val; 
}; 

template <typename Base> 
class Foo : public Base { 
public: 
    Foo(int v):Base(v) { } 
    // how can I initialize Base() class without referring to it's protected members? 
    Foo(const Foo<Base>& other) :Base(other.val) { } 
}; 

int main() { 
    Foo<Foobase> foo(5); 
    auto foo2 = foo; 
} 

class FooのコピーコンストラクタはBaseクラスを初期化するために保護されたメンバ変数を使用します。上記以外のBaseを初期化する他の方法はありますか?そのような場合のベストプラクティスは何ですか?

更新質問:@LogicStuffによって

回答は、質問のコピーコンストラクタの一部を明確ますが、移動のコンストラクタ質問に答えていません。 class Fooにもメンバー変数を持つことができる更新されたサンプルコードを参照してください。あなたは、単にBase年代を使用することができます

class Foobase { 
public: 
    Foobase(int v) :val(v) { } 
    Foobase(const Foobase&) = default; 
    Foobase(Foobase&&) noexcept = default; 
    Foobase& operator= (const Foobase&) = default; 
    Foobase& operator= (Foobase&&) noexcept = default; 
    void Print() const { 
    std::cout << val << std::endl; 
    } 
protected: 
    int val; 
}; 

template <typename Base> 
class Foo : public Base { 
public: 
    // works fine 
    Foo(std::string str, int v):Base(v), name(str) { } 

    // works fine 
    Foo(const Foo<Base>& other) :Base(other), name(other.name) { } 

    // I'm doubtful about this c'tor, if I move `other` for initializing Base, 
    // how can I initialize `name` variable? 
    Foo(Foo<Base>&& other) 
    :Base(std::move(other)), name(std::move(other.name) /* will this be valid?? */) { } 

    // can we have copy and assignment operator for this class? 

    void Print() { 
    std::cout << "name = " << name << std::endl; 
    Base::Print(); 
    } 

private: 
    std::string name; 
}; 

int main() { 
    Foo<Foobase> foo("foo", 5); 
    auto foo2 = std::move(foo); 
    foo2.Print(); 
} 
+0

なぜコピーコンストラクタを最初に定義していますか?ゼロの規則を使う。 – milleniumbug

+0

コピーコンストラクタはここでは例ですが、実際の使用シナリオでは5のルールに従います! – Pranav

+0

5のルールではありません。 *ゼロのルール*。あなたのケースでは、 'Foobase'はRule of Zeroに従い、' Foo'の中のメンバーは特別な扱いを必要としないので、 'Foo'クラスの特別なメンバーの*は書きません。必要なことをすべてやりなさい。 – milleniumbug

答えて

2

は、コンストラクタをコピーします。

Foo(const Foo<Base>& other) : Base(other) { } 

または全くそれを定義し、あなたがそこに余分な何かをするつもりはない場合は、コンパイラにそれを任せます。

実際には、このようになりますし、あなたの例では、まだコンパイルされます:

template <typename Base> 
class Foo : public Base { 
public: 
    using Base::Base; 
}; 

をあなたの編集後:

を今、あなたのように(2つのパラメータを取るコンストラクタを補足する必要がありますあなた):

template <typename Base> 
class Foo : public Base { 
public: 
    Foo(std::string str, int v) : Base(v), name(str) { } 

    void Print() { 
    std::cout << "name = " << name << std::endl; 
    Base::Print(); 
    } 

private: 
    std::string name; 
}; 

しかし、yそれ以外の場合は、コンパイラによって同じように生成される特別なメンバ関数も定義されています(つまり、正しいことを意味します)。元の例の場合もそうです。 Fooの両方のバージョンは移動可能です。

+0

答えのための@LogicStuffありがとう。それはコピーコンストラクタについての私の質問に答えますが、おそらくそれの移動コンストラクタの一部に答えることはありません。おそらく私は何かが欠けているでしょうか?更新された質問をご覧ください。ありがとう! – Pranav

+0

本当に3/5/0のルールに従ってください。この質問は純粋にあなたがそれをしていないことに基づいています。 – LogicStuff

+0

混乱して申し訳ありませんが、私は単純にすべてのコンストラクタをより小さなサンプルコードにすると定義していませんでした。 – Pranav

関連する問題