4

ポリモーフィズムやその他の手法について質問があります。次のスキームを検討してください。

#include <vector>
#include <memory>

using namespace std;

struct Base
{ };

struct Derived : Base
{ };

class group
{
    private:
        vector< unique_ptr<Base> > V;
    public:
        group( /* what to put here? */ )
        : V( /* again: how to construct V? */ )
        { }
}

ここでは、3 つのクラスがありBaseます。と呼ばれる派生クラスDerived。最後のクラスは、ポインターgroupを保持するラッパーとして機能します。Baseしかし、私は次のことを達成したいと思います:

  • 移動セマンティクスを使用します。コピーが含まれていてはなりません。コンストラクターがそれらを盗むため、呼び出し元はコンストラクターにいくつかの一時的な値を与えることができる必要があります。

    group my_wonderful_group( Base( /* parameters */ ) , Derived ( /* ... */ ) , Derived ( /* ... */ ) );
    
  • 初期V化リストで初期化します。そのようにして、constV修飾することができます(初期化リストでメンバーオブジェクトを初期化することには他のすべての利点がありますが)。

私はいくつかのことを試しましたが、それらは適切ではないように見えるか、単に概念的に私の目標からかけ離れています:

  • initializer_lists の要素は移動できません。unique_ptr可動のみです。
  • 可変個引数テンプレートは、 V constを作成するという目標に適合していないようです。initializer_lists は ( s のように) 異なる型のオブジェクトを保持できないため、vector最初はそれらについて考えましたが、どのように? 多くの例を読んだ後でも、可変個引数テンプレート コンストラクターを作成する方法、または回避策なしで作成することが可能であるとしても (つまり、 a 、a 、...を取るinit()関数を作成する) 、まだ理解できません。それで遊ぶ)。BaseDerived
  • 戻りunique_ptr<Base>、その引数を のコンストラクターに転送する関数を作成しますDerived。これにより、ユーザーフレンドリーなラッパーとしてgroupクラスに機能します。ただし、以下に添付されているコードで説明しているように、これはほとんど意味がありません。

これは私が持っているものです:

#include <string>
#include <vector>
#include <memory>
#include <initializer_list>
#include <iostream>

using namespace std;

struct Base
{
    string s;
    Base(Base && b) : s(move(b.s)) { }
    Base(const string & S) : s( S ) { }
};

struct Derived : Base
{
    Derived(const string & S) : Base( S ) { }
};

unique_ptr<Base>
BASE ( const string & S )
{
    return unique_ptr<Base>( new Base(S) );
}

unique_ptr<Base>
DERIVED ( const string & S )
{
    return unique_ptr<Base>( new Derived(S) );
}

class C
{
    private:
        vector< unique_ptr<Base> > V;
    public:
        template<typename ... T>
            C
            ( T ... t ) : V({ t... })
            { }

        void
            print
            ( void )
            {
                for ( const auto & x : this->V )
                    cout << x->s << endl;
            }
            ;
};


int main(void)
{
    C c( BASE("hola") , DERIVED("der1") , DERIVED("bor3") );
    c.print();
    return 0;
}

unique_ptrただし、のコンストラクターの引数 packが展開され、初期化に使用されるgroupコンマ区切りで配置されてinitializer_listいる場合、呼び出される[削除された] コピー コンストラクターの使用法について不満があります。V

私の質問は に行き着くと思いますvector、そして実際、1つに適用できます: vector<unique_ptr<Base>>( /* initialize with derived classes */ )。ポリモーフィズムは基本的な C++ であり、派生クラスのオブジェクトを保持することは非常に一般的な使用法であるため、これは以前に解決されたに違いないと思います。メモとして、私は を使用しますg++ 4.8.1

前もって感謝します。よろしく、カルリッシュ

PS:私の問題を部分的にカバーしているように見えるこの質問を読んだところです。

4

1 に答える 1

3

以下はすべての問題を解決するはずです:

#include <iostream>
#include <memory>
#include <string>
#include <vector>

using namespace std;

struct Base
{
    string s;
    Base(const Base& b) = delete;
    Base(Base && b) : s(move(b.s)) { }
    Base(const string & S) : s( S ) { }
};

struct Derived : Base
{
    Derived(const string & S) : Base( S ) { }
};

#if 1 // not in C++11
template <typename T, typename ... Ts>
std::unique_ptr<T> make_unique(Ts&&...args)
{
    return std::unique_ptr<T>(new T{std::forward<Ts>(args)...});
}
#endif

// vector<move_only> cannot be construct from initializer list :-/
// Use this work around
template <typename Base, typename ... Ts>
std::vector<std::unique_ptr<Base>> make_vector_of_unique(Ts&&... ts)
{
    std::unique_ptr<Base> init[] = {make_unique<Ts>(std::forward<Ts>(ts))...};
    return std::vector<std::unique_ptr<Base>> {
        std::make_move_iterator(std::begin(init)),
        std::make_move_iterator(std::end(init))};
}

class C
{
private:
    const std::vector< std::unique_ptr<Base> > V;
public:
    template<typename ... Ts>
    C(Ts&& ... t) : V(make_vector_of_unique<Base>(std::forward<Ts>(t)...))
    {}

    void print()
    {
        for (const auto & x : this->V)
            std::cout << x->s << std::endl;
    }
};

int main() {
    C c( Base("hola") , Derived("der1") , Derived("bor3") );
    c.print();
    return 0;
}
于 2013-12-31T03:00:21.503 に答える