문제

I'd like to implement a directory object which stores different types of object. Need to be able access the objects by name, get the actual pointer type and serialize it. The object I have in mind looks like this:

struct Object {
    std::string name;
    SomeType ptr;
};
struct Dir {
  std::string name;
  std::set<Object> objects;
};

"SomeType" I was thinking of using Boost::variant. But then it seems like I'd need to add object types into variant list during run-time. Even if I know the object types in a dir ahead, It would become

template <typename Typelist>
struct Object<Typelist> {
    std::string name;
    boost::variant<Typelist> objects;
};

where Typelist is different for different dirs. Then, having a dir of dirs would be the dynamic union of Typelist. It looks complicated. And it will soon hit the limit of 50 variant types. Alternative is Boost::Any to simplify semantics. But I'd like to iterate on the set of objects, and do stuff on it -- each object is a boost::fusion adapt_struct -- I want to fusion::for_each on each member of each object and display them, e.g.. Any alternatives or suggestions?

도움이 되었습니까?

해결책

All depends on how many different types and what kind of performance you need. If the number of object types are limited, then you are better off using a common base class, with specialization for each type.

The code below makes use of boost::shared_ptr and associated cast functionality. boost::shared_dynamic_cast can be used to cast back-and-forth between the base type and the specialized type.

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <list>

namespace stackoverflow
{

struct base_object
{
    enum type_t
    {
        directory = 0, file, link,

        n_types
    };

    const std::string name;
    const type_t type;

    base_object(const std::string& name, const type_t& type) :
            name(name), type(type) {
    }

    virtual ~base_object()
    {
    }
};

struct file_object : public base_object
{
    file_object(const std::string& name) : base_object(name, base_object::file)
    {
    }
};

struct symlink_object : public base_object
{
    symlink_object(const std::string& name) : base_object(name, base_object::link)
    {
    }
};

struct directory_object: public base_object
{
    std::list<boost::shared_ptr<base_object> > children;

    directory_object(const std::string& name) :
            base_object(name, base_object::directory)
    {
    }

    template < typename TypeTag >
    boost::shared_ptr< typename TypeTag::object_type > add(const std::string& name);
};

template < typename ObjectType >
struct tag
{
    typedef ObjectType object_type;
};

typedef tag< directory_object > directory;
typedef tag< file_object > file;
typedef tag< symlink_object > symlink;

template < typename TypeTag >
boost::shared_ptr< typename TypeTag::object_type > directory_object::add(const std::string& name)
{
    return boost::shared_dynamic_cast< typename TypeTag::object_type , base_object >(
            *children.insert(children.end(),
                    boost::shared_dynamic_cast< base_object, typename TypeTag::object_type >(
                            boost::make_shared< typename TypeTag::object_type >(name))));
}

}  // namespace stackoverflow


int main(void)
{
    using namespace stackoverflow;

    boost::shared_ptr< directory_object > root = boost::make_shared< directory_object >("/");
    root->add<directory>("etc")
            ->add<file>("hosts");
    root->add<directory>("tmp")
            ->add<file>("something.tmp");
    root->add<directory>("var")
            ->add<directory>("lib")
                ->add<directory>("mysql");
}

다른 팁

Th composite design pattern is the classical solution for a such thing

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top