2008-09-17 2 views
15

대부분의 성숙한 C++ 프로젝트는 자신의 반영 및 속성 시스템을 갖고있는 것으로 보입니다. 즉 문자열로 액세스 할 수 있고 자동으로 직렬화 할 수있는 속성을 정의하는 것입니다. 적어도 내가 참여한 많은 C++ 프로젝트는 바퀴를 다시 만들었습니다..C++의 속성 및 리플렉션 라이브러리는 무엇입니까?

는 특히, 컨테이너 반사를 지원하고 속성 C++에 대한 좋은 오픈 소스 라이브러리를 아십니까 :

  • 정의 RTTI 및 RTTI에 액세스 매크로
  • 를 통해 속성 및
  • 자동 코드를 통해 속성 속성 일련 화
  • 속성 수정 듣기 (예 : OnValueChanged)

답변

5

다음 두 가지 도구를 살펴볼 수 있습니다. 나는 그들 중 어느 누구도 사용하지 않았기 때문에, 그들이 얼마나 실용적인지 당신에게 말할 수는 없다.

XRTTI :

Xrtti 클래스와 이러한 클래스를 조작하는 방법과에 대한 반사 정보를 훨씬 풍부한 세트를 제공하는 C++ 표준 런타임 형식 시스템을 확장하는 도구 ++ 라이브러리 동반 C 그들의 회원.

OpenC++ :

OpenC는 C++ ++ 프론트 엔드 라이브러리 (렉서 + + DOM 파서/MOP) 및 소스 - 소스 번역기이다. OpenC++는 C++ 언어 도구, 확장 기능, 도메인 별 컴파일러 최적화 및 런타임 메타 객체 프로토콜 개발을 가능하게합니다.

+0

XRTTI에는 최신 Linux 배포판에 대한 업데이트 된 버전이 있습니다. OpenC++는 너무 오래된 것 같습니다. – minghua

2

일반적인 것은 아니지만 QT는 메타 컴파일러를 통해이를 지원하며 GPL입니다. QT 사람들과 이야기하는 것으로부터의 나의 이해는 이것이 순수한 C++에서는 가능하지 않다는 것입니다. 따라서 moc가 필요합니다.

2

반사 구현을 이식성 있고 보람있게 만들기 위해 표준화해야하는 것이 표준이 아니기 때문에 일반적으로 C++ 언어의 약점이 있습니다. 호출 규칙, 객체 레이아웃 및 심볼 맹 글링이 떠오르지 만 다른 것들도 있습니다.

표준의 방향이 없다는 것은 컴파일러 구현자가 다른 방식으로 작업을 수행한다는 것을 의미합니다. 즉, 리플렉션이 필요한 사람들이 휠을 다시 발명한다는 것을 의미하는 휴대용 리플렉션 라이브러리를 작성하려는 동기가 매우 적은 사람들을 의미합니다. 그러나 그들이 필요로하는 것만으로 충분합니다. 이것은 ad infinitum이 발생하고 여기 있습니다. 당신이 선택하든

C++ meets Reflection

, 아마 끔찍한 매크로를해야합니다 디버그 코드 또는 이상한 빌드 단계에 하드 :이 C++이 반사를 만날 때 당신은 무엇을 얻을

11

. 한 시스템이 DevStudio의 PDB 파일에서 직렬화 코드를 자동으로 생성하는 것을 보았습니다.

그러나 소규모 프로젝트의 경우 저장 /로드 기능을 작성하거나 스트리밍 연산자를 사용하는 것이 더 쉽습니다. 실제로 이것은 큰 프로젝트에도 적용될 수 있습니다. 이는 계속 진행되고 있으며 구조가 변경되면 코드를 변경해야합니다.

+1

내 앱에서 이미 Qt를 사용하지 않는 한, 저장해야하는 각 클래스에 대해 스트리밍 연산자를 만듭니다. – Branan

+0

+1 : 사진;) 농담. 나는 결론에 동의한다. 공예 연재를 사용하거나 다른 언어를 사용하십시오 :) – neuro

+0

+1 : 사진의 경우 실제로는 그렇지 않습니다. D – thecoshman

3

저는이 것들을 꽤 오래 동안 보았습니다.하지만 그들은 매우 무거운 경향이 있습니다. 그들은 당신이 상속을 사용하거나 이상한 생성자를 갖는 것을 막을 수도 있습니다. 결국 그들은 편리함 대신에 너무 많은 부담이되었습니다.

지금 사용하는 멤버를 노출하는이 방법은 매우 가볍기 때문에 직렬화를위한 클래스를 탐색하거나 "x"라는 모든 필드를 0으로 설정할 수 있습니다. 정적으로 결정되므로 매우 빠릅니다. 빌드 과정을 망칠 염려가없는 라이브러리 코드 나 코드 -gen의 레이어가 없습니다. 중첩 된 유형의 계층 구조로 일반화됩니다.

일부 작업을 자동화하기 위해 매크로를 사용하여 편집기를 설정하십시오.

struct point 
{ 
    int x; 
    int y; 

    // add this to your classes 
    template <typename Visitor> 
    void visit(Visitor v) 
    { 
     v->visit(x, "x"); 
     v->visit(y, "y"); 
    } 
}; 


/** Outputs any type to standard output in key=value format */ 
struct stdout_visitor 
{ 
    template <typename T> 
    void visit(const T& rhs) 
    { 
     rhs.visit(this); 
    } 

    template <typename Scalar> 
    void visit (const Scalar& s, const char* name) 
    { 
      std::cout << name << " = " << s << " "; 
    } 
} 
+0

나는 그것을 좋아하지만, 그것은 일반적인 해결책이 아니라는 것에 주목해야한다. 실제 정적 유형을 알지 못하면 즉시 중단됩니다. –

+0

좋은 접근 방법입니다. 한때'visit()'함수 템플릿을 생성하는 전 처리기를 만들었습니다. 그리고 JSON, 바이너리, 텍스트 등을 serialize하고 deserialize하는 몇 가지 펑터 ... No Wugly Macros. https://groups.google.com/d/msg/comp.lang.c++/Ila1Tn09mm4/nJVxl3SzpFUJ –

+0

감사합니다. 정말 간단하고 좋은 아이디어입니다. – user152508

11

완전히 다른 접근 방식을 사용하여 C++에서 반사를 제공하는 새로운 프로젝트가있다 : 캠프가. https://github.com/tegesoft/camp

CAMP는 precompiler를 사용하지 않고/properties/functions/... 클래스는 boost.python 또는 luabind와 유사한 구문을 사용하여 수동으로 선언됩니다. 물론 gccxml이나 open-C++과 같은 프리 컴파일러를 사용하여 원하는 경우이 선언을 생성 할 수 있습니다.

순수 C++ 및 부스트 헤더 만 기반으로하며 템플릿 메타 프로그래밍 덕분에 모든 종류의 바인딩 가능한 엔터티를 지원합니다 (예 : 상속 및 이상한 생성자는 문제가되지 않습니다).

MIT 라이센스 (이전의 LGPL)에 따라 배포됩니다.

+2

이것은 갈래로 나왔고 [Ponder로 계속] (http://billyquith.github.io/ponder/) – Nick

3

잠시 동안 보았습니다. 현재 가장 쉬운 해결책은 BOOST_FUSION_ADAPT_STRUCT 인 것 같습니다. 실질적으로 라이브러리/헤더가 있으면 BOOST_FUSION_ADAPT_STRUCT() 매크로에 구조체 필드를 추가하기 만하면됩니다 (the last segment of the code shows). 네, 많은 사람들이 언급 한 제한이 있습니다. 또한 리스너를 직접 지원하지 않습니다. 내가 들여다

다른 유망한 솔루션은 그러나 두 프로젝트에 외부 도구 의존성을 가져올 수있는 장애물이 될 것 같다

  • 캠프 및 XRTTI/gccxml 있습니다.
  • 몇 년 전 나는 perl c2ph/pstruct을 사용하여 gcc -gstabs의 출력에서 ​​메타 정보를 덤프했습니다. 이는 덜 관입 적이지만 더 완벽하게 작동하지만 더 이상 필요하지 않습니다.

부스트/__ cxa 접근 방식에 대해서는 모든 세부 정보를 파악한 후에는 구조 또는 필드를 추가/변경하는 것이 간단합니다. 우리는 현재이를 사용하여 dbus 위에 사용자 정의 유형 바인딩 계층을 작성하고, API를 직렬화하고, 관리 객체 서비스 서브 시스템에 대한 전송/RPC 세부 사항을 숨 깁니다.

+0

이것은/reflection /? Boost MPL/Fusion의 Sequence 개념을 어떻게 구조화하여 구조체를 적용 할 수 있는지 살펴볼 수 있으므로 필드를 반복 할 수 있습니다. 그러나 필드 이름을 가져 오거나 필드를 액세스하기 위해 이름을 사용하는 것은 문제가되지 않습니다. IIRC. – sehe

+0

@sehe : 보시다시피 필드 유형은 __cxa_demangle (typeid (t) .name())에 의해 인쇄됩니다. 구조체 디코더와 배열 디코더에 동일한 함수를 적용하여 모든 최상위 수준을 포함하여 모든 유형 및 배열 유형을 인쇄 할 수 있습니다. java vm이 내부 바이너리 목록의 모든 클래스/객체 목록을 유지한다고 생각하면이 예제에서 덤프하는 메타 데이터는 대략 그 수준에 있습니다. 낮은 수준의 정보 (런타임 주소 정보 포함)에서 필드에 액세스하기위한 코드 (문자열 또는 char [] 형식의 이름)를 작성해야합니다. 그것은 전체 반사 그림의 나머지 절반입니다. – minghua

+0

아. 따라서 대답의 가장 중요한 부분은 실제로 존재하지 않습니다. Hmmm 그것은 놀라웠다. 어쨌든, 나는'c2ph/pstruct' **에 대해 ** + 1을 할 것입니다. Oldschool,하지만 대부분의 장소에서 작동합니다. __cxa *는 정확하게 휴대 할 수 없습니다. ADAPT_STRUCT는 관련성이 낮고 작업하기 쉽고 자동화가 쉽지 않습니다. 매크로를 사용한다면 매크로를 사용할 수 있습니다 (Boost 또는 GCC ABI에 의존하지 않음). – sehe

0

자동 내성/반사 도구 키트.Qt와 같은 메타 컴파일러를 사용하고 메타 정보를 오브젝트 파일에 직접 추가하십시오. 직관적 인 사용하기 쉽습니다. 외부 종속성 없음. 심지어 std :: string을 자동으로 반영한 다음 스크립트에서 사용합니다. IDK