3

私は以下のように2つの異なるクラスを持っています:

class text
{ };

class element
{ };

そして、それらをに保存したいclass node

template <typename T>
class node
{
    T cargo;

    std::vector<void*> children;

    node(T cargo) : cargo(cargo)
    { };

    void add_child(T node)
    {
        this->children.push_back((void*) node);
    }
}

したがって、このようにノードを呼び出して、textelementの両方を格納します。

element div;
text msg;

node<element> wrapper(div);

wrapper.add_child(msg);

編集:私が使用するコンテンツを取得し、T typedef type;void ポインターを に変換します(type*)

それはあまりエレガントでも機能的でもないことは知っていますが、それを行う正しい方法がわかりません。それで、これが実際に受け入れられるかどうか、そしてそうでない場合は、適切な方法でそれを行う方法を教えてください.

前もって感謝します!

4

6 に答える 6

7
#include <vector>
using namespace std;

class Element {};
class Text {};
class Nothing {};

class Node
{
private:
    vector< Node* >     children_;
protected:
    Node() {}
public:
    void add( Node* p ) { children_.push_back( p ); }
    virtual ~Node() {}
};

template< class Cargo >
class CargoNode
    : public Node
{
private:
    Cargo   cargo_;
public:
    CargoNode(): cargo_() {}
};

typedef CargoNode< Element >    ElementNode;
typedef CargoNode< Text >       TextNode;
typedef CargoNode< Nothing >    RootNode;

int main()
{
    RootNode*   root    = new RootNode;

    root->add( new ElementNode );
    root->add( new ElementNode );
    root->add( new TextNode );
    root->add( new ElementNode );   
    // Etc.
}

乾杯 & hth.,

PS: このサンプル コードでは、エラー チェック、有効期間管理、反復などは省略されています。

于 2010-10-21T14:08:34.580 に答える
5

void* はほとんどの場合「悪い」(悪い定義の場合) と言えます。確かに、あなたがやろうとしていることを表現するより良い方法があるでしょう。このコードを書いているのが私で、入力する値の型がわかっている場合は、Boost.Variantの使用を検討します。私がそうしなかった場合 (たとえば、これは「埋める」ために他の誰かにライブラリとして提供された)、Boost.Anyを使用します。

例えば:

template <class T, class U>
struct node
{
    typedef boost::variant<T, U> child_type;

    std::vector<child_type> children;

    void add_child(T const &t)
    {
        children.push_back(t);
    }

    void add_child(U const &u)
    {
        children.push_back(u);
    }
};

...

node<text, element> n;
n.add_child(text("foo"));

非ブーストタイプの共用体ソリューション:

struct node
{
    struct child
    {
        int type; // 0 = text; 1 = element

        union 
        {
            text*    t;
            element* e;
        } u;
    };

    std::vector<child> children;

    void add_child(text* t)
    {
        child ch;
        ch.type = 0;
        ch.u.t  = t;

        children.push_back(ch);
    }

    void add_child(element* e)
    {
        child ch;
        ch.type = 1;
        ch.u.e  = t;

        children.push_back(ch);
    }
};

注: 型付き共用体を使用したメモリ管理には、もっと注意を払う必要があります。

于 2010-10-21T12:57:52.983 に答える
1

コンテナー値が少数のタイプに制限されている場合は、次のように使用boost::variantしてこれを実現できます。

#include <vector>
#include <boost/variant.hpp>

using namespace std;

class text
{ };

class element
{ };

template <typename T>
class node
{
    T cargo;

    static std::vector<boost::variant<text, element>> children;

    node(const T& cargo) : cargo(cargo)
    { };

    void add_child(const T& node)
    {
        children.push_back(boost::variant<text, element>(node));
    }
};

私は他のいくつかのモッズを自由に提案しました-コンストラクターとconstで値渡しの代わりに参照を使用します; それぞれが独自のコンテナを持つことは意味がないと思うので、コンテナを静的にします。この場合、 をマルチスレッドで使用するにはロックが必要です。これらのコメントは、最終的なソリューションで Boost を使用できるかどうかに関係なく適用されます。nodeadd_childchildrennode<T>add_child

ここに示すように、またはのvectorいずれかを使用して要素に対して操作を実行できます。このソリューションに使用するものに類似した反復の例:getstatic_visitorvector

class times_two_generic
    : public boost::static_visitor<>
{
public:

    template <typename T>
    void operator()( T & operand ) const
    {
        operand += operand;
        cout << operand << endl;
    }

};

std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );

times_two_generic visitor;
std::for_each(
      vec.begin(), vec.end()
   , boost::apply_visitor(visitor)
   );

出力は次のとおりです。

42

やあやあ

于 2010-10-21T13:38:02.357 に答える
1

これを行う場合、どのようにそれらを元に戻すことができますか? からvoid*、アドレスに実際に格納されているものを特定する方法はありません。

編集:常にキャストを行う場合は、T*単にパラメーターとして取ることができT*ます。

于 2010-10-21T12:42:52.273 に答える
1

の共有基本クラスを定義するとelementtext基本add_childクラスへのポインターを取得でき、ベクトルは基本クラスへのポインターを格納できます。

于 2010-10-21T12:43:12.960 に答える
0

まず、void ポインターを使用するのが「悪い」ということはありません。すべての慣例やブラブラを忘れて、自分のケースに最も適した方法を実行してください。

さて、あなたの特定のケースでは、これらの2つのクラスの間に何らかの接続がある場合、基本クラスを宣言して、それらの2つがそれを継承するようにすることができます。次に、その基本クラスのポインターのベクトルを宣言できます。

于 2010-10-21T12:43:07.607 に答える