2012-02-25 5 views
0

개체 계층 구조를 반복하고 객체 계층 구조가 컴포지션을 사용하여 결합 된 알려진 클래스 집합으로 구성됩니다. 나는 계층 적/컴포지션을 그래픽으로 보여주기 위해 객체 모델을 만들고 싶습니다. 구성은 몇 가지 규칙에 따라 수행되지만 유동적이고 유연합니다.알려진 클래스 집합 내에서의 반사

몇 가지 클래스 (25+)를 사용할 수 있으며 빌딩 블록의 수가 증가하고 있습니다. 다른 유형의 각 유형을 검색하면 가능한 많은 수의 조합이 가능합니다.

주어진 유형에 대해 다른 각 개체를 검색하고 재귀 적으로 개체 모델을 구축 할 수있는 큰 테이블을 만들 수 있지만 더 나은 방법이있을 수 있으므로 여기 전문가에게 묻습니다.

런타임에 함수/멤버 변수가 특정 유형에 있는지 여부를 알 수 있습니까?

내 예제 코드는 다음과 같습니다 :

#include <iostream> 

struct Generic {}; 

struct SimpleType {int toString(){return 0;}}; 

enum ETypeVal{eVal1 = 0, eVal2 = 1, eVal3 = 2}; 


template <typename ETypeVal val> 
struct Hello 
{ 
    int toString(){return 0;} 
}; 

template <> struct Hello<eVal2> 
{ 
    int toString(){return 1;} 
}; 

template <> struct Hello<eVal3> 
{ 
}; 


template <class Type> 
class TypeHasToString 
{ 
public: 
    typedef bool Yes; 
    typedef short No; 

    static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes)); 

private: 

    template <typename T, T> struct TypeCheck; 

    template <typename T> struct ToString 
    { 
     typedef int (T::*fptr)(); 
    }; 

    template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*); 
    template <typename T> static No HasToString(...); 
}; 

int main(int argc, char *argv[]) 
{ 
    // all this works fine 
    std::cout << TypeHasToString<Generic>::value << std::endl; 
    std::cout << TypeHasToString<SimpleType>::value << std::endl; 
    std::cout << TypeHasToString<Hello<eVal1>>::value << std::endl; 
    std::cout << TypeHasToString<Hello<eVal2>>::value << std::endl; 
    std::cout << TypeHasToString<Hello<eVal3>>::value << std::endl; 

    // Unable to deduce for type that are not known at compile time 
    // Is it possible to remove this limitation ? 
    for(int val = eVal1; val <= eVal3; val++) 
    { 
     std::cout << TypeHasToString< Hello< (ETypeVal)val > >::value << std::endl; 
    } 

    return 0; 
} 
+0

유형 범위는 컴파일시 'eVal1'에서 eVal3'으로 알려 지거나 예제의 버그입니까? – pmr

+0

Doxygen을 사용해 보셨습니까? 꽤 좋은 그래프를 출력한다고 생각합니다. –

+0

예제에서 볼 수있는 eVal1에서 eVal3 유형의 범위는 컴파일 타임에 enum이 아니라 integer로 알려져 있습니다. 이름이 바뀌지 않는 마지막 열거 형을 사용하여 클래스의 총 수를 알 수 있습니다. – Ram

답변

1

필자는 boost :: mpl을 사용하여 값의 반복 및 인쇄 작업을 수행했습니다. 이것들의 대부분은 그것들없이 가능해야하지만, 나는 그것을 사용하는 것을 강력히 권유한다. 또한 코드에서 몇 가지 사항을 수정했습니다. 또한 홈 브루 솔루션 대신 BOOST_HAS_XXX를 사용할 수도 있습니다 (SFINAE 스타일은 다소 어색합니다).

#include <iostream> 
#include <boost/mpl/vector.hpp> 
#include <boost/mpl/range_c.hpp> 
#include <boost/mpl/transform.hpp> 
#include <boost/mpl/for_each.hpp> 


struct Generic {}; 

struct SimpleType {int toString(){return 0;}}; 

enum ETypeVal{ eVal1 = 0, eVal2 = 1, eVal3 = 2}; 

template <ETypeVal val> 
struct Hello 
{ 
    int toString(){return 0;} 
}; 

template <> struct Hello<eVal2> 
{ 
    int toString(){return 1;} 
}; 

template <> struct Hello<eVal3> 
{ 
}; 


template <class Type> 
class TypeHasToString 
{ 
public: 
    typedef bool Yes; 
    typedef short No; 
private: 

    template <typename T, T> struct TypeCheck; 

    template <typename T> struct ToString 
    { 
    typedef int (T::*fptr)(); 
    }; 

    template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*); 
    template <typename T> static No HasToString(...); 

public: 
    static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes)); 
}; 

template<typename val> 
struct make_hello { typedef Hello< ETypeVal(val::value)> type; }; 

struct print_seq { 
    template<typename T> 
    void operator()(const T&) const { 
    std::cout << T::value << std::endl; 
    } 
}; 

int main() 
{ 
    using namespace boost::mpl; 
    // maybe have a last enum here 
    typedef range_c<int, eVal1, eVal3 + 1>::type range; 
    // range has no clear so we need the inserter 
    typedef transform<range, make_hello<_1>, back_inserter< vector0<> > >::type hellos; 
    typedef transform< hellos, TypeHasToString<_1> >::type booleans; 
    // namespace for clarity 
    boost::mpl::for_each<booleans>(print_seq()); 

    return 0; 
} 
0

나는 당신이이 경우에 런타임 다형성이 필요하다고 생각합니다. 이러한 종류의 문제에 템플릿 대신 인터페이스를 사용하십시오. 인터페이스는 객체의 메소드에 대한 지식을 제공하지만 멤버 변수에 대해서는 아무 것도 말하지 않습니다. 따라서 표준 C++에서 사용할 수있는 리플렉션이 없습니다 (C++에서 제공하는 유일한 것은 type_info 연산자로 어떤 경우에는 도움이 될 수 있음). 컴파일러에서 반사 기회를 얻을 수있는 확장 프로그램을 찾으려고 할 수 있습니다.

1

우리는 C++에서 런타임 반영을 가지고 있지 않습니다. 그러나 우리는 다른 것들을 가지고 있습니다. 대부분의 C++ 프로그래머는 리플렉션보다 낫습니다 ;-).

질문을 이해하면 일종의 개체 브라우저를 만들어야하며 모든 개체 유형을 알 수 있습니다. "당신은 모든 객체 유형을 알고 있습니다."라는 말은 "코드를 작성하지 않은 dll에서 포인터의 반대편 끝에 뭔가있는 객체를 얻지 못합니다"라는 의미입니다.

그래서 boost::fusion을 사용할 수 있습니까? 이 라이브러리는 집계를 통해 반복하고, 그렇게하면서 각 집계 멤버의 데이터 유형을 모두 검색하도록 설계되었습니다. 꽃 모양으로 넣어야한다면 구조체 멤버에 대한 반복자와 같습니다. 물론 use을 사용자 정의 유형으로 사용할 수 있습니다.

1

컴파일 타임에 런타임에 알 수 없습니다. 하나의 함수를 컴파일 할 때 알아야 할 코드가 있습니다. 당신은 당신이 검사하고 싶은 어떤 기능을 위해 매크로를 만들 수 있습니다. (매크로 면책 조항 : 매크로가 좋으면 BOOST_MPL_HAS_XXX_TEMPLATE_DEF의 작동 방식입니다.)

또는 boost :: fusion이 dsign에 의해 언급되었습니다. 하지만 나는 또 다른 하나를 선호합니다 : 부스트 :: 반영 (부스트에서 actully 아니 more info here). 매크로 구문이 더 쉽습니다 (매크로에서 유형을 언급 할 필요가 없음). 코드는 매우 가볍습니다. 그렇다면 boost :: mirror (download here)을 완료 한 기능이 아직 완료되지 않았고 훨씬 더 완벽하며 매크로 생성을위한 코드 생성기와 자바 스타일의 런타임 리플렉션이 있습니다.