C ++ 애플리케이션에 리플렉션을 추가하려면 어떻게해야합니까?


263

C ++ 클래스의 이름, 내용 (예 : 멤버 및 유형) 등을 조사 할 수 있기를 원합니다. 나는 관리되는 C ++이 아닌 네이티브 C ++을 말하고 있습니다. C ++이 RTTI를 사용하여 제한된 정보를 제공한다는 것을 알고 있습니다. 이 정보를 제공 할 수있는 추가 라이브러리 (또는 기타 기술)는 무엇입니까?


18
운이 좋으면 매크로 사전 처리 마법을 통해 수동으로 생성 하지 않으면 필요한 메타 데이터 가 존재 하지 않기 때문에 매크로 및 기타 사전 처리 없이는 수행 할 수 없습니다 .
jalf

6
RTTI에서 얻을 수있는 정보만으로는 실제로 반영하려는 대부분의 작업을 수행하기에 충분하지 않습니다. 예를 들어 클래스의 멤버 함수를 반복 할 수 없습니다.
Joseph Garvin

답변:


259

프리 프로세서가 필드에 대한 리플렉션 데이터를 생성하도록해야합니다. 이 데이터는 중첩 클래스로 저장 될 수 있습니다.

먼저, 전 처리기에서보다 쉽고 깔끔하게 작성하기 위해 형식화 된 표현을 사용합니다. 유형이 지정된 표현식은 유형을 괄호 안에 넣는 표현식입니다. 따라서 글 int x을 쓰는 대신에 글 을 쓸 것입니다 (int) x. 다음은 유형이 지정된 표현식에 도움이되는 몇 가지 편리한 매크로입니다.

#define REM(...) __VA_ARGS__
#define EAT(...)

// Retrieve the type
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
// Strip off the type
#define STRIP(x) EAT x
// Show the type without parenthesis
#define PAIR(x) REM x

다음으로, REFLECTABLE각 필드 (및 필드 자체)에 대한 데이터를 생성 하는 매크로를 정의합니다 . 이 매크로는 다음과 같이 호출됩니다.

REFLECTABLE
(
    (const char *) name,
    (int) age
)

따라서 Boost.PP 를 사용하여 각 인수를 반복하고 다음과 같은 데이터를 생성합니다.

// A helper metafunction for adding const to a type
template<class M, class T>
struct make_const
{
    typedef T type;
};

template<class M, class T>
struct make_const<const M, T>
{
    typedef typename boost::add_const<T>::type type;
};


#define REFLECTABLE(...) \
static const int fields_n = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__); \
friend struct reflector; \
template<int N, class Self> \
struct field_data {}; \
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

#define REFLECT_EACH(r, data, i, x) \
PAIR(x); \
template<class Self> \
struct field_data<i, Self> \
{ \
    Self & self; \
    field_data(Self & self) : self(self) {} \
    \
    typename make_const<Self, TYPEOF(x)>::type & get() \
    { \
        return self.STRIP(x); \
    }\
    typename boost::add_const<TYPEOF(x)>::type & get() const \
    { \
        return self.STRIP(x); \
    }\
    const char * name() const \
    {\
        return BOOST_PP_STRINGIZE(STRIP(x)); \
    } \
}; \

이것이하는 일은 fields_n클래스에서 반사 가능한 필드 수인 상수 를 생성하는 것입니다. 그런 다음 field_data각 필드에 대해 전문화 됩니다. 또한 reflector수업과 친구 가되어 비공개로도 필드에 액세스 할 수 있습니다.

struct reflector
{
    //Get field_data at index N
    template<int N, class T>
    static typename T::template field_data<N, T> get_field_data(T& x)
    {
        return typename T::template field_data<N, T>(x);
    }

    // Get the number of fields
    template<class T>
    struct fields
    {
        static const int n = T::fields_n;
    };
};

이제 필드를 반복하기 위해 방문자 패턴을 사용합니다. 0에서 필드 수까지 MPL 범위를 만들고 해당 인덱스의 필드 데이터에 액세스합니다. 그런 다음 필드 데이터를 사용자 제공 방문자에게 전달합니다.

struct field_visitor
{
    template<class C, class Visitor, class I>
    void operator()(C& c, Visitor v, I)
    {
        v(reflector::get_field_data<I::value>(c));
    }
};


template<class C, class Visitor>
void visit_each(C & c, Visitor v)
{
    typedef boost::mpl::range_c<int,0,reflector::fields<C>::n> range;
    boost::mpl::for_each<range>(boost::bind<void>(field_visitor(), boost::ref(c), v, _1));
}

이제 진실의 순간에 우리는 모든 것을 하나로 모았습니다. 반영 가능한 Person클래스를 정의하는 방법은 다음과 같습니다 .

struct Person
{
    Person(const char *name, int age)
        :
        name(name),
        age(age)
    {
    }
private:
    REFLECTABLE
    (
        (const char *) name,
        (int) age
    )
};

print_fields리플렉션 데이터를 사용하여 필드를 반복 하는 일반화 된 함수 는 다음과 같습니다 .

struct print_visitor
{
    template<class FieldData>
    void operator()(FieldData f)
    {
        std::cout << f.name() << "=" << f.get() << std::endl;
    }
};

template<class T>
void print_fields(T & x)
{
    visit_each(x, print_visitor());
}

print_fields플렉서블 Person클래스 와 함께 를 사용하는 예 :

int main()
{
    Person p("Tom", 82);
    print_fields(p);
    return 0;
}

어떤 출력 :

name=Tom
age=82

그리고 voila, 우리는 방금 C ++에서 100 줄 이하의 코드로 리플렉션을 구현했습니다.


106
리플렉션을 구현할 수 없다고 말하는 대신 리플렉션을 구현하는 방법을 보여 주신 분. SO를 훌륭한 리소스로 만드는 것은 이와 같은 답변입니다.
fearless_fool

4
Visual Studio에서이를 컴파일하려고하면 VS가 가변 매크로 확장을 올바르게 처리하지 못하므로 오류가 발생합니다. VS의 경우 다음을 추가 #define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tuple하고 #define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__)) TYPEOF (x)의 정의를 다음과 같이 변경하십시오.#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Phenglei Kai

'BOOST_PP_IIF_0'오류에 유형 이름이 지정되지 않습니다. 도와주세요.
Ankit Zalani

3
내 자신의 답변을 참조하십시오 - stackoverflow.com/a/28399807/2338477 내가 추출하고 모든 정의를 재 포장하고, 부스트 라이브러리가 필요하지 않습니다했습니다. 데모 코드로 xml에 직렬화를 제공하고 xml에서 복원합니다.
TarmoPikaro

106

reflection주위 에는 두 종류의 수영이 있습니다.

  1. 형식의 멤버를 반복하고 메서드 등을 열거하여 검사합니다.

    C ++에서는 불가능합니다.
  2. 클래스 유형 (클래스, 구조체, 공용체)에 메소드 또는 중첩 유형이 있는지 검사하여 다른 특정 유형에서 파생되었는지 검사합니다.

    이런 종류의 일은 C ++을 사용하여 가능합니다 template-tricks. boost::type_traits많은 것들에 사용하십시오 (유형이 완전한지 확인하는 것과 같이). 멤버 함수의 존재를 확인하려면 다음을 사용하십시오. 함수의 존재를 확인하기 위해 템플리트를 작성할 수 있습니까? . 특정 중첩 유형이 존재하는지 확인하려면 일반 SFINAE를 사용 하십시오 .

클래스가 가지고있는 메소드 수를 보거나 클래스 ID의 문자열 표현을 얻는 것과 같은 1) 달성 방법을 찾고 있다면 표준 C ++ 방법이 없다는 것이 두렵습니다. 둘 중 하나를 사용해야합니다

  • 메타 정보를 추가하여 코드를 변환하는 Qt Meta Object Compiler와 같은 메타 컴파일러.
  • 필요한 메타 정보를 추가 할 수있는 매크로로 구성된 프레임 워크입니다. 프레임 워크에 모든 메소드, 클래스 이름, 기본 클래스 및 필요한 모든 것을 알려 주어야합니다.

C ++는 속도를 염두에두고 만들어졌습니다. C # 또는 Java와 같은 고급 검사를 원한다면 아무런 노력없이 방법이 없다는 것을 두려워해야합니다.


122
C ++은 속도를 염두에두고 만들어졌지만, 철학은 "가능한 한 빨리"가 아니라 "사용하지 않으면 비용을 지불하지 않는다"는 것입니다. 언어가 그 철학에 맞는 방식으로 내성 검사를 구현할 수 있다고 믿습니다. C ++에는 언어가 부족합니다.
Joseph Garvin

8
@Joseph : 어떻게해야합니까? 모든 메타 데이터를 저장해야합니다. 사용하지 않더라도 비용을 지불해야합니다. 개별 유형을 "반사 지원"으로 표시 할 수없는 경우 기존 매크로 속임수를 사용할 수있는 곳이 거의 없습니다.
jalf

25
@jalf : 필요한 메타 데이터 만 컴파일 타임 리플렉션 만 고려한다면, 이것은 사소한 것입니다. 예를 들어 컴파일 타임 함수 members<T>는 T의 모든 멤버의 목록을 반환합니다. 런타임 리플렉션 (즉, 리플렉션과 RTTI 혼합)을 원한다면 컴파일러는 여전히 모든 리플렉션 된 기본 유형을 알고 있습니다. members<T>(T&)T = std :: string에 대해 인스턴스화되지 않을 가능성 이 높 으므로 std :: string 또는 파생 클래스의 RTTI를 포함 할 필요가 없습니다.
MSalters

9
리플렉스 라이브러리 (아래 참조)는 기존 코드의 속도를 늦추지 않고 C ++에 반영을 추가합니다. root.cern.ch/drupal/content/reflex
Joseph Lisee

6
@Joe : 리플렉션은 기존 코드의 속도를 늦추지 않습니다. 유형 정보 데이터베이스를 제공해야하기 때문에 전달 된 물건을 더 크게 만듭니다.
mmmmmmmm

56

조랑말을 좋아하지만 조랑말은 공짜가 아닙니다. :-피

http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI 는 당신이 얻을 것입니다. C ++에는 기본적으로 런타임에 사용할 수있는 완전히 설명 가능한 메타 데이터 인 생각과 같은 리플렉션이 존재하지 않습니다.


1
나는 두 번째 브래드. C ++ 템플릿은 다소 강력 할 수 있으며 부스트 '모든'라이브러리, 유형 특성, C ++ RTTI 등과 같은 다양한 '반사'유형 동작에 대한 풍부한 경험이있어서 많은 문제를 해결할 수 있습니다. 닉, 여기서 목표는 무엇입니까?
Aaron

7
조랑말 말에 찬성! 귀하의 답변도 가치가 있기 때문에 나는 두 번 공감했지만 슬프게도 하나만 얻었으므로 조랑말이 이겼습니다. :-)
Franci Penov 2011

6
나는 이것이 왜 영리한 반응인지 알지 못한다. 나는 이미 이것을 구현하기 위해 라이브러리 등에 대한 참조를 원한다고 말했다. 다양한 시스템에서 스크립트 액세스, 직렬화 등을 할 수 있습니다.
Nick

3
@ 닉 : 그는 이미 대답했다. 수행 할 수없고 데이터가 존재하지 않으므로 라이브러리에서이를 구현할 수 없습니다.
jalf

@jalf 프로그래밍 세계의 사람들이 '그것이 가능하지 않다'고 생각하고 '어떻게 모르겠어요'라고 말하는 것을 읽는 것이 여전히 이상합니다. 메타 데이터가 존재하지 않지만 매크로로 삽입 될 수 있음
Freddx L.

38

정보는 존재하지만 필요한 형식이 아니며 클래스를 내보내는 경우에만 존재합니다. 이것은 Windows에서 작동하지만 다른 플랫폼에 대해서는 모르겠습니다. 예를 들어 다음과 같이 스토리지 클래스 지정자를 사용하십시오.

class __declspec(export) MyClass
{
public:
    void Foo(float x);
}

이것은 컴파일러가 클래스 정의 데이터를 DLL / Exe에 빌드하게합니다. 그러나 리플렉션에 쉽게 사용할 수있는 형식이 아닙니다.

우리 회사에서는이 메타 데이터를 해석하는 라이브러리를 만들었으며 클래스 자체에 추가 매크로 등을 삽입하지 않고도 클래스를 반영 할 수 있습니다. 다음과 같이 함수를 호출 할 수 있습니다.

MyClass *instance_ptr=new MyClass;
GetClass("MyClass")->GetFunction("Foo")->Invoke(instance_ptr,1.331);

이것은 효과적으로 :

instance_ptr->Foo(1.331);

Invoke (this_pointer, ...) 함수에는 변수 인수가 있습니다. 분명히 이런 식으로 함수를 호출하면 const-safety 등과 같은 것들을 피할 수 있으므로 이러한 측면은 런타임 검사로 구현됩니다.

구문이 향상 될 수 있다고 확신하며 지금까지 Win32 및 Win64에서만 작동합니다. 우리는 클래스에 대한 자동 GUI 인터페이스, C ++에서 속성 생성, XML과의 스트리밍 등에서 실제로 유용하며 특정 기본 클래스에서 파생 될 필요가 없다는 것을 알게되었습니다. 수요가 충분하면 출시를 위해 모양을 바꿀 수 있습니다.


1
나는 당신이 생각 __declspec(dllexport)하고 빌드하는 동안 그러한 생성을 가능하게하면 .map 파일에서 정보를 검색 할 수 있다고 생각합니다 .
Orwellophile

18

C ++에서는 기본적으로 리플렉션이 지원되지 않습니다. 방어 테스트가 고통스럽기 때문에 슬픈 일입니다.

리플렉션을 수행하는 방법에는 여러 가지가 있습니다.

  1. 디버그 정보를 사용하십시오 (휴대용이 아님).
  2. 매크로 / 템플릿 또는 다른 소스 접근 방식으로 코드를 뿌립니다 (추악한 모양)
  3. clang / gcc와 같은 컴파일러를 수정하여 데이터베이스를 생성하십시오.
  4. Qt moc 접근 방식 사용
  5. 부스트 반영
  6. 정확하고 평평한 반사

첫 번째 링크는 가장 유망한 것으로 보이며 (mod는 clang에 사용) 두 번째 링크는 여러 가지 기법을 설명하며, 세 번째 링크는 gcc를 사용하는 다른 접근 방식입니다.

  1. http://www.donw.org/rfl/

  2. https://bitbucket.org/dwilliamson/clreflect

  3. https://root.cern.ch/how/how-use-reflex

이제 C ++ 리플렉션 작업 그룹이 있습니다. C ++ 14 @ CERN 관련 뉴스보기 :

13/08/17 편집 :

원래 게시물 이후 반영에 많은 잠재적 발전이 있었다. 다음은 다양한 기술과 상태에 대한 자세한 내용과 설명입니다.

  1. 간단히 말해서 정적 반사
  2. 정적 반사
  3. 정적 반사를위한 디자인

그러나 C ++에서 리플렉션을 지원하는 커뮤니티의 관심이 더 많지 않으면 가까운 미래에 C ++의 표준화 된 리플렉션 접근법에 대해서는 유망하지 않습니다.

다음은 마지막 C ++ 표준 회의의 피드백을 기반으로 현재 상태를 자세히 설명합니다.

13/12/2017 수정

리플렉션은 C ++ 20 이상 또는 아마도 TSR로 이동하는 것으로 보입니다. 그러나 움직임이 느립니다.

15/09/2018 수정

TS 초안이 투표를 위해 국가 기관에 발송되었습니다.

텍스트는 https://github.com/cplusplus/reflection-ts 에서 찾을 수 있습니다.

2019 년 11 월 7 일 수정

리플렉션 TS는 기능이 완성되었으며 여름 (2019)에 대한 의견과 투표를 위해 출품되었습니다.

메타 템플릿 프로그래밍 접근법은 더 단순한 컴파일 타임 코드 접근법 (TS에는 반영되지 않음)으로 대체되어야한다.

10/02/2020 수정

Visual Studio에서 리플렉션 TS를 지원하라는 요청이 있습니다.

저자 David Sankel의 TS에 대해 이야기하십시오.

2020 년 3 월 17 일 수정

반성 진행 중입니다. '2020-02 Prague ISO C ++위원회 여행 보고서'의 보고서는 여기에서 찾을 수 있습니다.

C ++ 23에서 고려할 사항에 대한 자세한 내용은 여기에서 확인할 수 있습니다 (Reflection에 대한 간단한 섹션 포함).

2020 년 6 월 4 일 편집

Jeff Preshing은 런타임 반영을위한 메커니즘을 포함하는 'Plywood'라는 새로운 프레임 워크를 발표했습니다. 자세한 내용은 여기를 참조하십시오.

도구와 접근 방식은 지금까지 가장 세련되고 사용하기 쉬운 것으로 보입니다.


1
서른 링크가 끊어졌습니다.
Mostowski Collapse

cern 링크가 수정되었습니다. 그들은 자주 통증을 느끼는 경향이 있습니다.
데미안 딕슨

이 답변은 컴파일 타임 반영에만 관련됩니까?
einpoklum

@einpoklum 리플렉션에 대한 현재의 유일한 솔루션은 일반적으로 메타 템플릿 코드 또는 매크로를 사용하는 컴파일 시간입니다. 최신 초안 TS는 런타임에 작동하는 것처럼 보이지만 필요한 메타 데이터를 저장하려면 올바른 컴파일러로 모든 라이브러리를 작성해야합니다.
Damian Dixon

@DamianDixon : 사실이 아닙니다. 몇 가지 런타임 리플렉션 라이브러리가 있습니다. 이제 당연히, 그들은 다소 어색하고 옵트 인하거나 컴파일러 승인이 필요하지만 여전히 존재합니다. 귀하의 의견을 이해하면서 컴파일 타임 반영 만 언급 한 경우 답변을 수정하여 명확하게 작성하십시오.
einpoklum

15

무엇을하려고하는지, RTTI가 요구 사항을 충족하는지 확인해야합니다. 나는 매우 구체적인 목적을 위해 자체 의사 반사를 구현했습니다. 예를 들어, 시뮬레이션에서 출력 할 내용을 유연하게 구성 할 수 있기를 원했습니다. 출력되는 클래스에 상용구 코드를 추가해야했습니다.

namespace {
  static bool b2 = Filter::Filterable<const MyObj>::Register("MyObject");
} 

bool MyObj::BuildMap()
{
  Filterable<const OutputDisease>::AddAccess("time", &MyObj::time);
  Filterable<const OutputDisease>::AddAccess("person", &MyObj::id);
  return true;
}

첫 번째 호출은이 객체를 필터링 시스템에 추가합니다. BuildMap() 메소드를 메소드를 파악합니다.

그런 다음 구성 파일에서 다음과 같이 할 수 있습니다.

FILTER-OUTPUT-OBJECT   MyObject
FILTER-OUTPUT-FILENAME file.txt
FILTER-CLAUSE-1        person == 1773
FILTER-CLAUSE-2        time > 2000

을 포함하는 일부 템플릿 매직을 통해 boost런타임시 (구성 파일을 읽을 때) 일련의 메서드 호출로 변환되므로 상당히 효율적입니다. 꼭 필요한 경우가 아니면이 작업을 수행하지 않는 것이 좋습니다.하지만 그렇게하면 정말 멋진 작업을 수행 할 수 있습니다.


항상 true를 반환하는 이러한 함수를 좋아해야합니다.) 이것은 정적 초기화 순서 문제의 면역이라고 가정합니까?
paulm

14

Qt 사용하는 것이 좋습니다 .

상업용 라이센스뿐만 아니라 오픈 소스 라이센스도 있습니다.


1
나는 이것을 보았지만 매크로를 사용하고 메타 데이터 코드를 생성하기 위해 소스 코드를 파싱해야합니다. 이 추가 단계를 피하고 싶습니다. C ++ 라이브러리 또는 간단한 매크로를 사용하고 싶습니다. 그래도 아이디어 주셔서 감사합니다.
Nick

10
QT 또는 유사한 접근법을 구현하는 다른 라이브러리가 가장 좋습니다
jalf

5
컴파일 타임에 지불하거나 런타임에 지불하십시오-지불하는 방법 중 하나!
Martin Beckett

13

리플렉션으로 무엇을하려고합니까?
당신은 부스트 사용할 수있는 유형의 특성대해서 typeof 컴파일시 반사의 제한된 형태로 라이브러리를. 즉, 템플릿에 전달 된 유형의 기본 속성을 검사하고 수정할 수 있습니다.


13

편집 : 캠프 는 더 이상 유지되지 않습니다; 두 가지 포크를 사용할 수 있습니다 :

  • 하나는 CAMP 라고도하며 동일한 API를 기반으로합니다.
  • Ponder 는 부분 재 작성이며 Boost가 필요하지 않으므로 선호됩니다. C ++ 11을 사용하고 있습니다.

CAMP 는 C ++ 언어에 반영된 MIT 라이센스 라이브러리 (이전 LGPL)입니다. 컴파일 과정에서 특정 전처리 단계가 필요하지 않지만 바인딩을 수동으로 만들어야합니다.

현재 Tegesoft 라이브러리는 Boost를 사용하지만 더 이상 Boost가 필요없는 C ++ 11을 사용 하는 포크 도 있습니다 .


11

나는 당신이 한 번 한 후에했던 것과 같은 것을했고, 어느 정도의 수준의 반영과 높은 수준의 기능에 대한 접근이 가능하지만 유지 보수 두통은 그만한 가치가 없을 수도 있습니다. 필자의 시스템은 Objective-C의 메시지 전달 및 전달 개념과 비슷한 위임을 통해 UI 클래스를 비즈니스 논리와 완전히 분리하는 데 사용되었습니다. 그렇게하는 방법은 심볼을 매핑 할 수있는 기본 클래스를 만드는 것입니다 (문자열 풀을 사용했지만 총 유연성보다 속도 및 컴파일 타임 오류 처리를 선호하는 경우 열거 형으로 수행 할 수 있음). 순수한 함수 포인터이지만 Boost.Function과 비슷한 기능-당시에는 액세스 할 수 없었습니다). 값을 나타낼 수있는 공통 기본 클래스가있는 한 멤버 변수에 대해 동일한 작업을 수행 할 수 있습니다. 전체 시스템은 키-밸류 코딩 및 위임의 확고한 격차였으며, 시스템을 사용하는 모든 클래스를 합법적 인 호출과 일치시키기 위해 시스템을 사용하는 모든 클래스를 얻는 데 필요한 상당한 시간이 걸리는 부작용이 몇 가지있었습니다. : 1) 모든 클래스는 헤더를 포함하거나 가짜 기본 클래스를 작성하지 않고도 다른 클래스의 모든 메소드를 호출 할 수 있으므로 인터페이스가 컴파일러에 대해 사전 정의 될 수 있습니다. 그리고 2) 멤버 변수의 게터와 세터는 값을 변경하거나 액세스하는 것이 모든 객체의 기본 클래스에서 항상 2 개의 메소드를 통해 수행되므로 스레드 안전을 쉽게 만들 수 있습니다. 전체 시스템은 키-밸류 코딩 및 위임의 확고한 격차였으며, 시스템을 사용하는 모든 클래스를 합법적 인 호출과 일치시키기 위해 시스템을 사용하는 모든 클래스를 얻는 데 필요한 상당한 시간이 걸리는 부작용이 몇 가지있었습니다. : 1) 모든 클래스는 헤더를 포함하거나 가짜 기본 클래스를 작성하지 않고도 다른 클래스의 모든 메소드를 호출 할 수 있으므로 인터페이스가 컴파일러에 대해 사전 정의 될 수 있습니다. 그리고 2) 멤버 변수의 게터와 세터는 값을 변경하거나 액세스하는 것이 모든 객체의 기본 클래스에서 항상 2 개의 메소드를 통해 수행되므로 스레드 안전을 쉽게 만들 수 있습니다. 전체 시스템은 키-밸류 코딩 및 위임의 확고한 격차였으며, 시스템을 사용하는 모든 클래스를 합법적 인 호출과 일치시키기 위해 시스템을 사용하는 모든 클래스를 얻는 데 필요한 상당한 시간이 걸리는 부작용이 몇 가지있었습니다. : 1) 모든 클래스는 헤더를 포함하거나 가짜 기본 클래스를 작성하지 않고도 다른 클래스의 모든 메소드를 호출 할 수 있으므로 인터페이스가 컴파일러에 대해 사전 정의 될 수 있습니다. 그리고 2) 멤버 변수의 게터와 세터는 값을 변경하거나 액세스하는 것이 모든 객체의 기본 클래스에서 항상 2 개의 메소드를 통해 수행되므로 스레드 안전을 쉽게 만들 수 있습니다. 1) 모든 클래스는 헤더를 포함하거나 가짜 기본 클래스를 작성하지 않고도 다른 클래스의 모든 메소드를 호출 할 수 있으므로 인터페이스가 컴파일러에 대해 사전 정의 될 수 있습니다. 그리고 2) 멤버 변수의 게터와 세터는 값을 변경하거나 액세스하는 것이 모든 객체의 기본 클래스에서 항상 2 개의 메소드를 통해 수행되므로 스레드 안전을 쉽게 만들 수 있습니다. 1) 모든 클래스는 헤더를 포함하거나 가짜 기본 클래스를 작성하지 않고도 다른 클래스의 모든 메소드를 호출 할 수 있으므로 인터페이스가 컴파일러에 대해 사전 정의 될 수 있습니다. 그리고 2) 멤버 변수의 게터와 세터는 값을 변경하거나 액세스하는 것이 항상 모든 객체의 기본 클래스에서 2 개의 메소드를 통해 수행되므로 스레드 안전을 쉽게 만들 수 있습니다.

또한 C ++에서는 쉽지 않은 정말 이상한 일을 할 가능성이있었습니다. 예를 들어, 자체를 포함하여 모든 유형의 임의 항목을 포함하는 Array 객체를 만들고 모든 배열 항목에 메시지를 전달하고 반환 값을 수집하여 Lisp에서 매핑하는 것과 같이 동적으로 새 배열을 만들 수 있습니다. 다른 하나는 키-값 관찰의 구현으로, 데이터를 지속적으로 폴링하거나 불필요하게 디스플레이를 다시 그리는 대신 백엔드 클래스 멤버의 변경 사항에 즉시 응답하도록 UI를 설정할 수있었습니다.

아마도 더 흥미로운 것은 클래스에 대해 정의 된 모든 메소드와 멤버를 문자열 형식으로 덤프 할 수 있다는 것입니다.

귀찮게하는 시스템의 단점 : 모든 메시지와 키-값을 추가하는 것은 매우 지루합니다. 반사가없는 것보다 느립니다. 당신이보고 증오로 성장할 것입니다 boost::static_pointer_castboost::dynamic_pointer_cast 폭력적인 열정을 가진 당신의 코드베이스를 통해 모든; 강력한 형식의 시스템의 한계는 여전히 존재합니다. 실제로는 조금 숨겨져 있으므로 명확하지 않습니다. 당신의 줄에있는 오타도 재미 있거나 놀랍지 않습니다.

이와 같은 것을 구현하는 방법에 관해서는 : 공유하고 약한 포인터를 공통베이스 (광산은 매우 상상적으로 "Object"라고 불렀습니다)에 사용하고 사용하려는 모든 유형에 대해 파생하십시오. 내가했던 방식대로 Boost.Function을 설치하는 것이 좋습니다. 기능 포인터 호출을 감싸기 위해 약간의 사용자 정의 쓰레기와 못생긴 매크로가있었습니다. 모든 것이 매핑되었으므로 객체 검사는 모든 키를 반복하는 문제입니다. 내 클래스는 본질적으로 C ++ 만 사용하여 가능한 한 Cocoa의 직접 리핑에 가깝기 때문에 이와 같은 것을 원한다면 Cocoa 문서를 청사진으로 사용하는 것이 좋습니다.


안녕, @Michael; 여전히 소스 코드가 있습니까, 아니면 제거 했습니까? 마음에 들지 않으면 살펴보고 싶습니다.
RandomDSdevel

으악, 당신의 이름을 잘못 입력했습니다! 없음 당연 내가 답장을 가진 적이 없어 ...
RandomDSdevel

10

RTTR (런타임 타입 리플렉션, github 참조) 이라는 C ++에 리플렉션을위한 새로운 라이브러리가 있습니다. ) .

인터페이스는 C #의 리플렉션과 유사하며 RTTI없이 작동합니다.


8

C ++ 시절부터 내가 알고있는 두 가지 반사 형 솔루션은 다음과 같습니다.

1) RTTI를 사용하면 모든 클래스를 '객체'기본 클래스에서 파생시킬 수있는 경우 반사와 같은 동작을 빌드 할 수있는 부트 스트랩을 제공합니다. 이 클래스는 GetMethod, GetBaseClass 등과 같은 일부 메소드를 제공 할 수 있습니다. 이러한 메소드의 작동 방식에 따라 유형을 장식하기 위해 매크로를 수동으로 추가해야합니다.

2) 컴파일러 객체에 액세스 할 수있는 다른 옵션은 DIA SDK 를 사용하는 것 입니다. 올바르게 기억하면 pdb를 열 수 있습니다. pdb는 C ++ 유형의 메타 데이터를 포함해야합니다. 필요한 것을 수행하는 것으로 충분할 수 있습니다. 이 페이지 는 예를 들어 클래스의 모든 기본 유형을 얻는 방법을 보여줍니다.

이 두 솔루션 모두 조금 추악합니다! C #의 고급 스러움을 높이기 위해 약간의 C ++과 같은 것은 없습니다.

행운을 빕니다.


그것은 당신이 거기에서 제안한 DIA SDK와 함께 교묘하고 거대한 핵입니다.
Sqeaky

7

편집 : 2017 년 2 월 7 일 현재 깨진 링크가 업데이트되었습니다.

아무도 이것을 언급하지 않았다고 생각합니다.

CERN에서는 C ++에 대해 전체 리플렉션 시스템을 사용합니다.

CERN 반사 . 잘 작동하는 것 같습니다.


@ j4nbur53 이정표에 도달 한 것 같아 링크가 끊어졌습니다 : root.cern.ch
Germán Diago

이 링크가 root.cern.ch/root/doc/ROOTUsersGuideHTML/ch07.html 챕터 리플렉스 라는 의미 입니까?
Mostowski Collapse

root.cern.ch/how/how-use-reflex 사용해보십시오 . Reflex는 헤더 파일을 구문 분석하고 C ++ 내부 검사 코드 / 라이브러리를 생성하는 생성기로 작동하여 간단한 API에 연결하여 사용할 수 있습니다.
Adam Ryczkowski

6

이 질문은 지금 조금 낡았습니다 (오늘 왜 오래된 질문을 계속하는지 모르겠습니다).하지만 컴파일 타임 반영을 소개 하는 BOOST_FUSION_ADAPT_STRUCT 에 대해 생각하고 있었습니다 .

물론 이것을 런타임 반영에 매핑하는 것은 당신에게 달려 있으며 너무 쉽지는 않지만이 방향으로는 가능하지만 반대는 아닙니다. :)

실제로 매크로를 캡슐화하는 매크로 BOOST_FUSION_ADAPT_STRUCT는 런타임 동작을 얻는 데 필요한 메소드를 생성 할 수 있다고 생각합니다 .


2
minghua (원래 게시물을 편집 한 사람)에 의해 : 나는이 BOOST_FUSION_ADAPT_STRUCT 솔루션을 파고 결국 예제를 만들었습니다. 이 새로운 SO 질문 -C ++을 boost fusion adapt_struct와 함께 중첩 구조체 필드로 반복하십시오 .
Matthieu M.

맛있어요! 작년 한 해 동안 여기저기서 힌트를 보았습니다. 그들이 지금까지 관련되어 있음을 알지 못했습니다. 그들은 매우 고무적이었습니다.
minghua

6

Dominic Filion의 "C ++에서 리플렉션을위한 템플릿 사용"기사가 흥미로울 것 같습니다. 게임 프로그래밍 보석 5의 1.4 절에 있습니다. 불행히도 나는 나와 함께 사본을 가지고 있지 않지만, 당신이 요구하는 것을 설명한다고 생각하기 때문에 그것을 찾으십시오.


4

숙고하다 는이 질문에 대한 답으로 C ++ 리플렉션 라이브러리입니다. 나는 옵션을 고려하고 모든 상자를 똑딱 거리는 옵션을 찾을 수 없으므로 스스로 선택하기로 결정했습니다.

이 질문에 대한 답은 많지만 톤을 많이 사용하지 않거나 Boost를 사용하고 싶지 않습니다. Boost는 훌륭한 라이브러리이지만, 더 단순하고 컴파일 시간이 빠른 작은 맞춤형 C ++ 0x 프로젝트가 많이 있습니다. C ++ 11을 지원하지 않는 C ++ 라이브러리를 래핑하는 것과 같이 외부에서 클래스를 장식 할 수 있다는 이점도 있습니다. 더 이상 Boost가 필요하지 않은 것은 C ++ 11을 사용하는 CAMP 포크입니다 .


4

리플렉션은 본질적으로 컴파일러가 런타임 코드가 쿼리 할 수있는 코드에서 발자국으로 남기기로 결정한 것에 관한 것입니다. C ++는 사용하지 않는 것에 대해 비용을 지불하지 않는 것으로 유명합니다. 대부분의 사람들은 리플렉션을 사용하거나 원하지 않기 때문에 C ++ 컴파일러는 아무것도 기록하지 않음으로써 비용을 피합니다 . 있습니다.

따라서 C ++은 리플렉션을 제공하지 않으며 다른 답변에서 언급 한 것처럼 일반적인 규칙으로 "시뮬레이션"하기가 쉽지 않습니다.

"기타 기술"에서 리플렉션 언어가없는 경우 컴파일 타임에 원하는 정보를 추출 할 수있는 도구를 얻습니다.

우리 DMS 소프트웨어 재 설계 툴킷 명시 적 langauge 정의에 의해 파라미터 컴파일러 기술을 일반화한다. 그것은 C, C ++, Java, COBOL, PHP 등에 대한 언어 정의를 가지고 있습니다 ...

C, C ++, Java 및 COBOL 버전의 경우 구문 분석 트리 및 기호 테이블 정보에 대한 완전한 액세스를 제공합니다. 이 심볼 테이블 정보에는 "반사"에서 원하는 데이터 종류가 포함됩니다. 당신의 목표는 필드 또는 몇 가지 방법들을 열거하는 경우 어떻게 그들과 함께 뭔가를, DMS는 임의의 방법으로 심볼 테이블에서 찾을 내용에 따라 코드를 변환하는 데 사용할 수 있습니다.


3

여기에서 다른 라이브러리를 찾을 수 있습니다. http://www.garret.ru/cppreflection/docs/reflect.html 디버그 정보에서 유형 정보를 가져오고 프로그래머가이 정보를 제공하도록하는 두 가지 방법을 지원합니다.

나는 또한 내 프로젝트에 대한 반성에 관심이 있고이 라이브러리를 찾았습니다. 아직 시도하지는 않았지만이 녀석의 다른 도구를 사용해 보았습니다 .-)


3

Classdesc http://classdesc.sf.net을 확인 하십시오 . 클래스 "설명자"의 형태로 리플렉션을 제공하고, 표준 C ++ 컴파일러 (예 : Visual Studio 및 GCC와 함께 작동하는 것으로 알려져 있음)와 작동하며 소스 코드 주석이 필요하지 않습니다 (어려운 상황을 처리하기 위해 일부 pragma가 존재하지만) ). 10 년 이상 개발되어 왔으며 여러 산업 규모 프로젝트에 사용되었습니다.


1
스택 오버플로에 오신 것을 환영합니다. 이 답변은 주제에 관한 것이지만, 귀하가이 소프트웨어의 저자라는 것을 지적하는 것이 중요합니다. 편견없는 권장 사항이 아님을 분명히하기 위해 :-)
Matthew Strawbridge

2

C ++에서 리플렉션을 원할 때이 기사를 읽고 거기에서 본 내용 을 개선했습니다. 죄송합니다. 나는 결과를 소유하지 않지만 ... 내가 가지고있는 것을 확실히 얻을 수 있습니다.

필자는 현재 필자가 생각할 때 inheritable_linearly를 사용하여 반사 가능한 유형의 정의를 훨씬 쉽게 정의하는 방법을 연구하고 있습니다. 나는 실제로 그것에 상당히 멀었지만 여전히 갈 길이 있습니다. C ++ 0x의 변경 사항은이 영역에서 많은 도움이 될 것입니다.


2

C ++에 여전히이 기능이없는 것 같습니다. 그리고 C ++ 11은 리플렉션도 연기했습니다 ((

일부 매크로를 검색하거나 직접 만드십시오. Qt는 또한 리플렉션에 도움이 될 수 있습니다 (사용 가능한 경우).


2

리플렉션은 C ++에서 기본적으로 지원되지 않지만 구현하기가 어렵지 않습니다. 나는이 위대한 기사를 발견했다 : http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html

이 기사는 매우 간단하고 기초적인 반사 시스템을 구현하는 방법을 자세히 설명합니다. 그것의 가장 건강에 좋은 해결책을 부여하지 않았고, 분류 할 거친 가장자리가 남아 있지만 내 요구에 충분했습니다.

요점-리플렉션이 올바르게 수행되면 갚을 수 있으며 C ++에서 완전히 가능합니다.


2

자동 검사 / 반사 툴킷 "IDK"의 존재를 알리고 싶습니다. Qt와 같은 메타 컴파일러를 사용하고 메타 정보를 객체 파일에 직접 추가합니다. 사용하기 쉽다고합니다. 외부 의존성이 없습니다. 또한 std :: string을 자동으로 반영한 다음 스크립트에서 사용할 수도 있습니다. 제발 봐 IDK


2

비교적 간단한 C ++ 리플렉션을 찾고 있다면-다양한 소스 매크로 / 정의에서 수집하여 작동 방식을 설명했습니다. 여기에서 헤더 파일을 다운로드 할 수 있습니다.

https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h

정의 세트와 그 위에 기능 :

https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/ 얼룩 / 마스터 /TypeTraits.h

샘플 애플리케이션은 git 저장소에도 있습니다. https://github.com/tapika/TestCppReflect/

설명과 함께 여기에 부분적으로 복사하겠습니다.

#include "CppReflect.h"
using namespace std;


class Person
{
public:

    // Repack your code into REFLECTABLE macro, in (<C++ Type>) <Field name>
    // form , like this:

    REFLECTABLE( Person,
        (CString)   name,
        (int)       age,
...
    )
};

void main(void)
{
    Person p;
    p.name = L"Roger";
    p.age = 37;
...

    // And here you can convert your class contents into xml form:

    CStringW xml = ToXML( &p );
    CStringW errors;

    People ppl2;

    // And here you convert from xml back to class:

    FromXml( &ppl2, xml, errors );
    CStringA xml2 = ToXML( &ppl2 );
    printf( xml2 );

}

REFLECTABLEdefine은 클래스 이름 + 필드 이름을 offsetof- 와 함께 사용 하여 메모리의 특정 필드가있는 위치를 식별합니다. 나는 가능한 한에 대한 .NET 용어를 데리러 시도하지만 1이 아닌 1로 전체 C ++ 반사 모델에 상주 그래서 C ++와 C #은, 다른 TypeInfoFieldInfo클래스를.

pugi xml 파서를 사용하여 데모 코드를 xml로 가져 와서 XML에서 다시 복원했습니다.

따라서 데모 코드로 생성 된 출력은 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<People groupName="Group1">
    <people>
        <Person name="Roger" age="37" />
        <Person name="Alice" age="27" />
        <Person name="Cindy" age="17" />
    </people>
</People>

TypeTraits 클래스 및 부분 템플릿 사양을 통해 타사 클래스 / 구조 지원을 활성화 할 수도 있습니다. CString 또는 int와 유사한 방식으로 고유 한 TypeTraitsT 클래스를 정의 할 수 있습니다. 예제 코드 참조

https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195

이 솔루션은 Windows / Visual Studio에 적용됩니다. 다른 OS / 컴파일러로 이식 할 수는 있지만 그렇게하지는 않았습니다. (솔루션이 정말 마음에 든다면 도움을 드릴 수 있습니다.)

이 솔루션은 여러 서브 클래스가있는 한 클래스의 일회성 직렬화에 적용 가능합니다.

그러나 클래스 부분을 직렬화하거나 기능 리플렉션 호출이 생성하는 기능을 제어하는 ​​메커니즘을 찾고 있다면 다음 솔루션을 살펴볼 수 있습니다.

https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel

자세한 내용은 YouTube 비디오에서 찾을 수 있습니다.

C ++ 런타임 타입 리플렉션 https://youtu.be/TN8tJijkeFE

C ++ 리플렉션 작동 방식에 대해 좀 더 깊이 설명하려고합니다.

샘플 코드는 다음과 같습니다.

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp

c.General.IntDir = LR"(obj\$(ProjectName)_$(Configuration)_$(Platform)\)";
c.General.OutDir = LR"(bin\$(Configuration)_$(Platform)\)";
c.General.UseDebugLibraries = true;
c.General.LinkIncremental = true;
c.CCpp.Optimization = optimization_Disabled;
c.Linker.System.SubSystem = subsystem_Console;
c.Linker.Debugging.GenerateDebugInformation = debuginfo_true;

그러나 여기서 각 단계는 실제로 C ++ 속성을 사용하여 함수 호출을 발생 __declspec(property(get =, put ... )시킵니다.

C ++ 데이터 형식, C ++ 속성 이름 및 클래스 인스턴스 포인터에 대한 전체 정보를 경로 형태로 수신하고 해당 정보를 기반으로 인터넷을 통해 XML, json을 생성하거나 직렬화 할 수 있습니다.

이러한 가상 콜백 함수의 예는 다음에서 찾을 수 있습니다.

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp

함수 ReflectCopy및 가상 함수 참조::OnAfterSetProperty .

그러나 주제가 실제로 고급이기 때문에 먼저 비디오를 확인하는 것이 좋습니다.

개선 아이디어가 있으시면 언제든지 저에게 연락하십시오.


1

C ++에서의 리플렉션은 각 멤버에 대해 몇 가지 메소드를 실행해야하는 경우에 매우 유용합니다 (예 : 직렬화, 해싱, 비교). 매우 간단한 구문으로 일반적인 솔루션을 제공했습니다.

struct S1
{
    ENUMERATE_MEMBERS(str,i);
    std::string str;
    int i;
};
struct S2
{
    ENUMERATE_MEMBERS(s1,i2);
    S1 s1;
    int i2;
};

여기서 ENUMERATE_MEMBERS는 매크로이며, 나중에 설명합니다 (UPDATE).

다음과 같이 int 및 std :: string에 대한 직렬화 함수를 정의했다고 가정하십시오.

void EnumerateWith(BinaryWriter & writer, int val)
{
    //store integer
    writer.WriteBuffer(&val, sizeof(int));
}
void EnumerateWith(BinaryWriter & writer, std::string val)
{
    //store string
    writer.WriteBuffer(val.c_str(), val.size());
}

그리고 우리는 "비밀 매크로"근처에 일반적인 기능을 가지고 있습니다.;)

template<typename TWriter, typename T>
auto EnumerateWith(TWriter && writer, T && val) -> is_enumerable_t<T>
{
    val.EnumerateWith(write); //method generated by ENUMERATE_MEMBERS macro
}

이제 쓸 수 있습니다

S1 s1;
S2 s2;
//....
BinaryWriter writer("serialized.bin");

EnumerateWith(writer, s1); //this will call EnumerateWith for all members of S1
EnumerateWith(writer, s2); //this will call EnumerateWith for all members of S2 and S2::s1 (recursively)

따라서 구조체 정의에 ENUMERATE_MEMBERS 매크로를 사용하면 원래 유형을 건드리지 않고 직렬화, 비교, 해싱 및 기타 항목을 작성할 수 있습니다. 유일한 요구 사항은 열거 자별로 열거 할 수없는 각 유형에 대해 "EnumerateWith"메소드를 구현하는 것입니다 (BinaryWriter와 같은) . 일반적으로 프로젝트의 모든 유형을 지원하려면 10-20 "단순"유형을 구현해야합니다.

이 매크로는 런타임에 생성 / 파괴를 구성하기 위해 오버 헤드가 0이어야하고, T.EnumerateWith ()의 코드는 요청시 생성되어야하며,이를 템플릿 인라인 함수로 만들 수 있습니다. 모든 이야기는 각 구조체에 ENUMERATE_MEMBERS (m1, m2, m3 ...)를 추가하는 것입니다. 멤버 유형별로 특정 메서드를 구현하는 것은 모든 솔루션에서 필수이므로 오버 헤드로 가정하지 않습니다.

업데이트 : ENUMERATE_MEMBERS 매크로의 매우 간단한 구현이 있습니다 (그러나 열거 가능한 구조체의 상속을 지원하기 위해 약간 확장 될 수 있음)

#define ENUMERATE_MEMBERS(...) \
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) const { EnumerateWithHelper(enumerator, __VA_ARGS__ ); }\
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) { EnumerateWithHelper(enumerator, __VA_ARGS__); }

// EnumerateWithHelper
template<typename TEnumerator, typename ...T> inline void EnumerateWithHelper(TEnumerator & enumerator, T &...v) 
{ 
    int x[] = { (EnumerateWith(enumerator, v), 1)... }; 
}

// Generic EnumerateWith
template<typename TEnumerator, typename T>
auto EnumerateWith(TEnumerator & enumerator, T & val) -> std::void_t<decltype(val.EnumerateWith(enumerator))>
{
    val.EnumerateWith(enumerator);
}

이 15 줄의 코드에는 타사 라이브러리가 필요하지 않습니다.)


1

Boost :: Hana 라이브러리에서 BOOST_HANA_DEFINE_STRUCT 를 사용하여 구조체에 대한 멋진 정적 반사 기능을 얻을 수 있습니다 .
Hana는 유스 케이스뿐만 아니라 많은 템플릿 메타 프로그래밍을 위해 매우 다양합니다.


1

랜덤 액세스 반사 중 배열에서 사용할 수 또는 배열 액세스 같은 느낌에 모든 필드 / 유형 정보가 설계 - 라이브러리는 매우 쉽고 직관적 반사 있도록합니다. C ++ 17 용으로 작성되었으며 Visual Studios, g ++ 및 Clang과 함께 작동합니다. 라이브러리는 헤더 전용이므로 "Reflect.h"를 프로젝트에 복사하여 사용하면됩니다.

반영된 구조체 나 클래스는 반영하는 클래스의 이름과 필드의 이름을 제공하는 REFLECT 매크로가 필요합니다.

class FuelTank {
    public:
        float capacity;
        float currentLevel;
        float tickMarks[2];

    REFLECT(() FuelTank, () capacity, () currentLevel, () tickMarks)
};

이것이 전부입니다. 리플렉션을 설정하는 데 추가 코드가 필요하지 않습니다. 선택적으로 수퍼 클래스 (첫 번째 인수의 괄호로 묶음)와 필드 주석 (주석을 지정할 필드 앞에 괄호로 묶음)을 제공하여 수퍼 클래스를 순회하거나 필드에 추가 컴파일 시간 정보를 추가 할 수 있습니다 (예 : Json : : 무시).

필드를 통한 루핑은 다음과 같이 간단 할 수 있습니다.

for ( size_t i=0; i<FuelTank::Class::TotalFields; i++ )
    std::cout << FuelTank::Class::Fields[i].name << std::endl;

객체 인스턴스를 반복하여 필드 값 (읽거나 수정할 수 있음) 및 필드 유형 정보에 액세스 할 수 있습니다.

FuelTank::Class::ForEachField(fuelTank, [&](auto & field, auto & value) {
    using Type = typename std::remove_reference<decltype(value)>::type;
    std::cout << TypeToStr<Type>() << " " << field.name << ": " << value << std::endl;
});

JSON 라이브러리 RandomAccessReflection의 상단에 내장되어있는 읽기 또는 쓰기, 재귀 어떤 반사 분야뿐만 아니라 배열과 STL 컨테이너를 통과 할 수에 대한 자동 식별 적절한 JSON 출력 표현.

struct MyOtherObject { int myOtherInt; REFLECT(() MyOtherObject, () myOtherInt) };
struct MyObject
{
    int myInt;
    std::string myString;
    MyOtherObject myOtherObject;
    std::vector<int> myIntCollection;

    REFLECT(() MyObject, () myInt, () myString, (Reflected) myOtherObject, () myIntCollection)
};

int main()
{
    MyObject myObject = {};
    std::cout << "Enter MyObject:" << std::endl;
    std::cin >> Json::in(myObject);
    std::cout << std::endl << std::endl << "You entered:" << std::endl;
    std::cout << Json::pretty(myObject);
}

위와 같이 실행될 수 있습니다 ...

Enter MyObject:
{
  "myInt": 1337, "myString": "stringy", "myIntCollection": [2,4,6],
  "myOtherObject": {
    "myOtherInt": 9001
  }
}


You entered:
{
  "myInt": 1337,
  "myString": "stringy",
  "myOtherObject": {
    "myOtherInt": 9001
  },
  "myIntCollection": [ 2, 4, 6 ]
}

또한보십시오...


0

다음과 같은 함수에 대한 포인터를 선언하면 :

int (*func)(int a, int b);

이 기능에 메모리에 장소를 할당 할 수 있습니다 (필수 libdldlopen).

#include <dlfcn.h>

int main(void)
{
    void *handle;
    char *func_name = "bla_bla_bla";
    handle = dlopen("foo.so", RTLD_LAZY);
    *(void **)(&func) = dlsym(handle, func_name);
    return func(1,2);
}

간접을 사용하여 로컬 심볼을로드하려면 dlopen호출 바이너리 ( argv[0])를 사용할 수 있습니다 .

(이외의 다른 이에 대한 유일한 요구 사항 dlopen(), libdldlfcn.h인수 및 함수의 유형을 알고있다).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.