2013-10-22 7 views
3

다른 유형의 객체를 저장하는 디렉토리 객체를 구현하고 싶습니다. 이름으로 객체에 액세스 할 수 있어야하고 실제 포인터 유형을 가져 와서 직렬화해야합니다. 내가 생각하는 객체는 다음과 같습니다.오브젝트 디렉토리 구현 : boost :: any, boost :: variant 또는?

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

"SomeType"나는 Boost :: variant를 사용하려고 생각했습니다. 그러나 런타임시 변형 목록에 객체 유형을 추가해야하는 것처럼 보입니다. 나는 앞서 디렉토리에서 개체 유형을 알고있다하더라도, 그것은 Typelist 다른 DIRS 다릅니다

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

이 될 것입니다. 그런 다음 dirs의 dir을 갖는 것은 유형 목록의 동적 결합입니다. 그것은 복잡해 보입니다. 그리고 곧 50 가지 변형 유형의 한계에 부딪 칠 것입니다. 대안은 Boost :: Any로 의미를 단순화합니다. 하지만 객체 세트를 반복하고 싶습니다. 각 객체는 boost :: fusion adapt_struct입니다. 각 객체의 각 멤버에 fusion :: for_each를 표시하고 싶습니다. 어떤 대안이나 제안?

+0

디렉토리의 임의 항목을 모델링하는 기본 클래스는 옵션이 아니겠습니까? 그런 다음 특수 오브젝트에 대한 shared_ptr 또는 일반 포인터를 유지 한 다음 액세스 할 때이를 캐스트 할 수 있습니다. –

+0

그것은 옵션 중 하나입니다. 그러나 일단 기본 클래스를 저장하고 나면, 어떤 타입의 타입을 사용할 수 있는지, 어떻게 실제 타입으로 유용한 것을 하는지를 아는 것이 중요합니다. typeinfo를 저장하는 것이 static_cast (t)을 할 수있는 것처럼 보이지 않습니다. 여기서 "T"가 필요합니다. – surfcode

답변

2

모든 의존하는 등의 일을위한 솔루션과 성능의 종류이다. 객체 유형의 수가 제한되어 있으면 공통 기본 클래스를 사용하여 각 유형을 전문화하는 것이 좋습니다.

아래 코드는 boost::shared_ptr 및 관련 캐스트 기능을 사용합니다. boost::shared_dynamic_cast은 기본 유형과 특수 유형간에 앞뒤로 캐스트하는 데 사용할 수 있습니다.

#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"); 
} 
+0

감사합니다! 이전에는 boost :: any를 사용하고 typeinfo를 사용하여 "any"유형 방문자 펑터를 저장한다고 생각했습니다. 템플릿 기반 태그 유형을 사용하면 훨씬 효율적입니다. – surfcode

1

composite design pattern 당신이 필요로하는 고전 얼마나 많은 다른 유형에

+0

나는 그것이 질문하고있는 것에 대한 답이라고 생각하지 않는다. 일부는 리프가 될 것이며 일부는 디렉터에서 합성 된 것이라고 이해합니다. 문제는 잎의 경우 Object 클래스의 "SomeType"에 대한 실제 C++ 유형이어야합니다. – surfcode

+0

복합 디자인 패턴; 그것은 나에게 새로운 것이었다. 나는 그것을 전에했다. 그러나 결코 디자인 패턴이 존재할 것이라고 생각하지 않았습니다. 이러한 패턴의 가장 일반적인 사용은 XML/DOM 처리에 있습니다. – kingstonian