मैं C ++ एप्लिकेशन में प्रतिबिंब कैसे जोड़ सकता हूं?


263

मैं इसके नाम, सामग्री (अर्थात सदस्यों और उनके प्रकारों) आदि के लिए एक C ++ वर्ग का आत्मनिरीक्षण करने में सक्षम होना चाहूंगा, मैं यहां देशी C ++ की बात कर रहा हूं, C ++ प्रबंधित नहीं, जिसमें प्रतिबिंब है। मुझे लगता है कि C ++ RTTI का उपयोग करके कुछ सीमित जानकारी की आपूर्ति करता है। कौन सी अतिरिक्त लाइब्रेरी (या अन्य तकनीकें) इस जानकारी की आपूर्ति कर सकती हैं?


18
कठिन भाग्य, आप इसे मैक्रोज़ और अन्य प्रीप्रोसेसिंग के बिना नहीं कर सकते, क्योंकि आवश्यक मेटाडेटा तब तक मौजूद नहीं है जब तक कि आप मैन्युअल रूप से इसे कुछ मैक्रो प्रीप्रोसेसिंग जादू के माध्यम से नहीं बनाते हैं।
jalf

6
आरटीटीआई से आप जो जानकारी प्राप्त कर सकते हैं, वह उन अधिकांश कामों के लिए पर्याप्त नहीं है जिन्हें आप वास्तव में प्रतिबिंब के लिए चाहते हैं। आप उदाहरण के लिए एक वर्ग के सदस्य कार्यों पर पुनरावृति नहीं कर सकते।
जोसेफ गार्विन

जवाबों:


260

आपको जो करने की आवश्यकता है वह है प्रीप्रोसेसर फ़ील्ड के बारे में प्रतिबिंब डेटा उत्पन्न करना। यह डेटा नेस्टेड कक्षाओं के रूप में संग्रहीत किया जा सकता है।

सबसे पहले, इसे आसान बनाने के लिए और क्लीनर बनाने के लिए इसे प्रीप्रोसेसर में हम टाइप की गई अभिव्यक्ति का उपयोग करेंगे। एक टाइप की गई अभिव्यक्ति सिर्फ एक अभिव्यक्ति है जो टाइप को कोष्ठक में रखती है। इसलिए लिखने के बजाय 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

और वॉइला, हमने कोड की 100 लाइनों के तहत, C ++ में प्रतिबिंब लागू किया है।


106
कुदोस यह दिखाने के लिए कि यह कैसे किया जा सकता है, कहने के बजाय। यह इस तरह के उत्तर हैं जो SO को एक महान संसाधन बनाते हैं।
निर्भय_फूल

4
ध्यान दें कि यदि आप विजुअल स्टूडियो के तहत इसे संकलित करने का प्रयास करते हैं, तो आपको एक त्रुटि मिलेगी क्योंकि वीएस वैरिएड मैक्रो विस्तार को ठीक से नहीं संभालता है। 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' का नाम नहीं है। क्या आप मदद कर सकते हैं
अंकित जलानी

3
मेरा खुद का जवाब देखें - stackoverflow.com/a/28399807/2338477 मैंने सभी डिफाइन को हटा दिया है, और लाइब्रेरी को बढ़ावा देने की जरूरत नहीं है। डेमो कोड के रूप में मैं xml को क्रमबद्धता प्रदान कर रहा हूं और xml से पुनर्स्थापित कर रहा हूं।
TarmoPikaro

107

दो तरह के reflectionतैराकी हैं।

  1. एक प्रकार के सदस्यों पर पुनरावृत्ति द्वारा निरीक्षण, इसके तरीकों और इतने पर enumerating।

    C ++ के साथ यह संभव नहीं है।
  2. एक वर्ग-प्रकार (क्लास, स्ट्रक्चर, यूनियन) की विधि या नेस्टेड प्रकार की जाँच करके निरीक्षण किया जाता है, जो किसी अन्य विशेष प्रकार से लिया गया है।

    सी ++ का उपयोग करके इस तरह की बात संभव है template-tricksboost::type_traitsकई चीजों के लिए उपयोग करें (जैसे कि क्या एक प्रकार का अभिन्न अंग है) की जाँच करें। सदस्य फ़ंक्शन की मौजूदगी की जाँच के लिए, क्या फ़ंक्शन के अस्तित्व की जांच के लिए टेम्पलेट लिखना संभव है? । यह जाँचने के लिए कि क्या एक निश्चित नेस्टेड प्रकार मौजूद है, सादे SFINAE का उपयोग करें ।

यदि आप 1 को पूरा करने के तरीकों की तलाश कर रहे हैं), जैसे कि कक्षा में कितने तरीके हैं, या कक्षा आईडी का स्ट्रिंग प्रतिनिधित्व प्राप्त करना पसंद है, तो मुझे डर है कि ऐसा करने का कोई मानक C ++ तरीका नहीं है। आपको या तो उपयोग करना है

  • एक मेटा कंपाइलर जैसे क्यूटी मेटा ऑब्जेक्ट कंपाइलर जो आपके कोड को अतिरिक्त मेटा informations जोड़कर अनुवाद करता है।
  • मैक्रो का एक फ्रेमवर्क कांस्टेन्शन जो आपको आवश्यक मेटा-informations जोड़ने की अनुमति देता है। आपको सभी विधियों, वर्ग-नाम, आधार-वर्ग और इसके लिए आवश्यक सभी चीजों को बताना होगा।

C ++ को ध्यान में गति के साथ बनाया गया है। यदि आप उच्च-स्तरीय निरीक्षण चाहते हैं, जैसे C # या Java है, तो मुझे डर है कि मुझे आपको बताना होगा कि कुछ प्रयास के बिना कोई रास्ता नहीं है।


122
C ++ गति को ध्यान में रखकर बनाया गया है, लेकिन दर्शन "जितना संभव हो उतना तेज़ नहीं है," इसके बजाय, "यदि आप इसका उपयोग नहीं करते हैं तो आप इसके लिए भुगतान नहीं करते हैं।" मेरा मानना ​​है कि किसी भाषा के लिए आत्मनिरीक्षण को उस तरह से लागू करना संभव है जो उस दर्शन के साथ फिट बैठता है, C ++ में इसका अभाव है।
जोसफ गार्विन

8
@ जोसेफ: यह कैसे किया जाना चाहिए? इसे सभी मेटाडेटा को संग्रहीत करने की आवश्यकता होगी। इसका मतलब है कि आपको इसके लिए भुगतान करना होगा, भले ही आप इसका उपयोग न करें। (जब तक आप व्यक्तिगत प्रकारों को "सहायक प्रतिबिंब" के रूप में चिह्नित नहीं कर सकते हैं, लेकिन तब हम लगभग नीचे हैं जहां हम मौजूदा मैक्रो चालन का उपयोग कर सकते हैं।
jalf

25
@ जैलफ: केवल मेटाडेटा जिसकी आवश्यकता हो सकती है। यदि हम केवल संकलन-समय प्रतिबिंब पर विचार करते हैं, तो यह तुच्छ है। उदाहरण के लिए, एक संकलन-समय फ़ंक्शन, members<T>जो T के सभी सदस्यों की एक सूची देता है। यदि हम रनटाइम प्रतिबिंब (यानी आरटीटीआई मिश्रित प्रतिबिंब के साथ) चाहते हैं, तो संकलक को अभी भी सभी प्रतिबिंबित आधार प्रकार पता होंगे। यह काफी संभावना है members<T>(T&)कि टी = एसटीडी :: स्ट्रिंग के लिए कभी भी त्वरित नहीं किया जाएगा, इसलिए आरटीटीआई के लिए एसटीटी :: स्ट्रिंग या इसके व्युत्पन्न वर्गों को शामिल करने की आवश्यकता नहीं है।
MSALERS

9
रिफ्लेक्स लाइब्रेरी (नीचे उल्लेख किया गया है) C ++ में मौजूदा कोड को धीमा किए बिना प्रतिबिंब जोड़ता है: root.cern.ch/drupal/content/reflex
जोसेफ लिसे

6
@ जो: प्रतिबिंब मौजूदा कोड को धीमा नहीं करता है। यह केवल वितरित सामान को बड़ा बनाता है (क्योंकि आपको एक प्रकार की जानकारी डेटाबेस को वितरित करना है ...)।
mmmmmmmm

57

और मैं एक टट्टू प्यार करता हूँ, लेकिन टट्टू मुक्त नहीं हैं। :-P

http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI वही है जो आप प्राप्त करने जा रहे हैं। आप जैसा विचार कर रहे हैं वैसा ही प्रतिबिंब - रनटाइम पर पूरी तरह से वर्णनात्मक मेटाडेटा उपलब्ध है - बस डिफ़ॉल्ट रूप से C ++ के लिए मौजूद नहीं है।


1
मैं दूसरे ब्रैड। C ++ टेम्प्लेट बल्कि शक्तिशाली हो सकते हैं, और विभिन्न 'प्रतिबिंब' प्रकार के व्यवहार के आसपास अनुभव का खजाना होता है, जैसे कि 'किसी भी' लाइब्रेरी को बढ़ावा देना, टाइप लक्षण, C ++ RTTI आदि जो कई समस्याओं को हल कर सकते हैं, जिनके लिए प्रतिबिंब हल किया जाता है। तो निक, यहाँ तुम्हारा क्या लक्ष्य है?
हारून

7
टट्टू टिप्पणी के लिए Upvote! मैं दो बार उत्थान करूंगा, क्योंकि आपका उत्तर भी इसका हकदार है, लेकिन दुख की बात है कि मुझे केवल एक ही मिला, इसलिए टट्टू जीत गए। :-)
फ्रांसे पेनोव 3

6
मैं वास्तव में नहीं मिलता कि यह एक चतुर प्रतिक्रिया क्यों है। मैंने पहले ही कहा है कि मैं इसे लागू करने के लिए पुस्तकालयों आदि के संदर्भ चाहूंगा। प्रतिबिंब / आत्मनिरीक्षण विभिन्न प्रणाली के लिए स्क्रिप्ट पहुंच, क्रमांकन आदि की अनुमति के लिए है
निक

3
@ निक: वह पहले से ही जवाब दिया है। यह नहीं किया जा सकता है, डेटा मौजूद नहीं है, और इसलिए, कोई भी लाइब्रेरी आपके लिए इसे लागू करने में सक्षम नहीं है।
जलफ

@jalf अभी भी मेरे लिए अजीब है कि प्रोग्रामिंग दुनिया के लोग यह कहते हुए पढ़ते हैं कि 'यह संभव नहीं' जैसा है और 'मुझे नहीं पता कि कैसे'। यकीन है कि मेटाडेटा मौजूद नहीं है, लेकिन मैक्रोज़ के साथ डाला जा सकता है
फ्रेडिक्स एल।

39

जानकारी मौजूद है - लेकिन उस प्रारूप में नहीं, जिसकी आपको आवश्यकता है, और केवल तभी जब आप अपनी कक्षाओं का निर्यात करते हैं। यह विंडोज में काम करता है, मैं अन्य प्लेटफार्मों के बारे में नहीं जानता। उदाहरण के लिए, स्टोरेज-क्लास स्पेसियर्स का उपयोग करना:

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, ...) फ़ंक्शन में परिवर्तनशील तर्क होते हैं। जाहिर है इस तरह से एक समारोह में बुलाकर आप कॉन्स्ट-सेफ्टी जैसी चीजों को दरकिनार कर रहे हैं, इसलिए इन पहलुओं को रनटाइम चेक के रूप में लागू किया जाता है।

मुझे यकीन है कि वाक्य रचना में सुधार किया जा सकता है, और यह केवल Win32 और Win64 पर अब तक काम करता है। हमने पाया है कि यह कक्षाओं के लिए स्वचालित GUI इंटरफेस बनाने, C ++ में प्रॉपर्टी बनाने, XML से स्ट्रीमिंग करने आदि के लिए वास्तव में उपयोगी है, और विशिष्ट बेस क्लास से प्राप्त करने की कोई आवश्यकता नहीं है। यदि पर्याप्त मांग है तो शायद हम इसे रिलीज के लिए आकार दे सकते हैं।


1
मुझे लगता है कि आपका मतलब है __declspec(dllexport)और यदि आप निर्माण के दौरान इस तरह के निर्माण को सक्षम करते हैं तो आप एक .map फ़ाइल से जानकारी पुनः प्राप्त कर सकते हैं।
Orwellophile

17

प्रतिबिंब बॉक्स के बाहर C ++ द्वारा समर्थित नहीं है। यह दुखद है क्योंकि यह रक्षात्मक परीक्षण को एक दर्द बनाता है।

परावर्तन करने के लिए कई दृष्टिकोण हैं:

  1. डीबग जानकारी (गैर पोर्टेबल) का उपयोग करें।
  2. मैक्रो / टेम्प्लेट या किसी अन्य स्रोत दृष्टिकोण (बदसूरत दिखता है) के साथ अपना कोड छिड़कें
  3. डेटाबेस बनाने के लिए क्लैंग / gcc जैसे कंपाइलर को संशोधित करें।
  4. Qt moc दृष्टिकोण का उपयोग करें
  5. बूस्ट रिफ्लेक्ट
  6. सटीक और सपाट प्रतिबिंब

पहला लिंक सबसे आशाजनक लगता है (मॉड का उपयोग करता है), दूसरा तकनीक की एक संख्या पर चर्चा करता है, तीसरा 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 को संपादित करें

प्रतिबिंब सी ++ 20 या संभवतः टीएसआर की ओर बढ़ रहा है। हालांकि आंदोलन धीमा है।

15/09/2018 संपादित करें

एक टीएस को राष्ट्रीय निकायों को मतपत्र के लिए भेजा गया है।

पाठ यहां पाया जा सकता है: https://github.com/cplusplus/reflection-ts

संपादित करें 11/07/2019

प्रतिबिंब TS पूरी तरह से फीचर है और गर्मियों (2019) पर टिप्पणी और वोट के लिए बाहर है।

मेटा-टेम्प्लेट प्रोग्रामिंग दृष्टिकोण को सरल संकलन समय कोड दृष्टिकोण (टीएस में परिलक्षित नहीं) के साथ प्रतिस्थापित किया जाना है।

10/02/2020 को संपादित करें

यहाँ विज़ुअल स्टूडियो में प्रतिबिंब टीएस का समर्थन करने का अनुरोध है:

लेखक डेविड सांकल द्वारा टीएस पर बात करें:

17 मार्च 2020 को संपादित करें

प्रतिबिंब पर प्रगति की जा रही है। '2020-02 प्राग आईएसओ सी ++ कमेटी ट्रिप रिपोर्ट' की रिपोर्ट यहां मिल सकती है:

C ++ 23 के लिए क्या विचार किया जा रहा है, इस पर विवरण यहां पाया जा सकता है (प्रतिबिंब पर संक्षिप्त खंड शामिल है):

4 जून 2020 को संपादित करें

जेफ प्रेशिंग द्वारा 'प्लाइवुड' नामक एक नई रूपरेखा जारी की गई है जिसमें रनटाइम रिफ्लेक्शन के लिए एक तंत्र है। अधिक विवरण यहां मिल सकता है:

उपकरण और दृष्टिकोण अब तक का उपयोग करने के लिए सबसे पॉलिश और आसान लग रहे हैं।


1
कड़ी कड़ी टूट गई है।
मोस्टोव्स्की

अब कर्न लिंक को ठीक किया जाना चाहिए। वे बहुत बार टूट जाते हैं जो एक दर्द है।
डेमियन डिक्सन

क्या यह जवाब केवल संकलन-समय के प्रतिबिंब का संबंध है?
einpoklum

@einpoklum प्रतिबिंब के लिए केवल वर्तमान समाधान संकलन समय है, आमतौर पर मेटा-टेम्पलेट कोड या मैक्रो के साथ। नवीनतम ड्राफ्ट टीएस ऐसा लगता है कि इसे रनटाइम के लिए काम करना चाहिए, लेकिन आपके पास आवश्यक मेटाडेटा को संग्रहीत करने के लिए सही कंपाइलर के साथ सभी पुस्तकालयों का निर्माण करना होगा।
डेमियन डिक्सन

@DamianDixon: यह सच नहीं है। वहाँ कई रन-टाइम प्रतिबिंब पुस्तकालय। अब, दी गई, वे बल्कि क्लूनी हैं और या तो ऑप्ट-इन हैं या कंपाइलर नोड्स की आवश्यकता है, लेकिन वे अभी भी मौजूद हैं। यदि, जैसा कि मैं आपकी टिप्पणी को समझता हूं, तो आपने केवल संकलन-समय प्रतिबिंब को संदर्भित किया है, कृपया इसे स्पष्ट करने के लिए अपना उत्तर संपादित करें।
einpoklum

15

आपको यह देखने की ज़रूरत है कि आप क्या करने की कोशिश कर रहे हैं, और अगर आरटीटीआई आपकी आवश्यकताओं को पूरा करेगा। मैंने कुछ विशेष उद्देश्यों के लिए अपना स्वयं का छद्म प्रतिबिंब लागू किया है। उदाहरण के लिए, मैं एक बार लचीले ढंग से कॉन्फ़िगर करने में सक्षम होना चाहता था कि एक सिमुलेशन आउटपुट क्या होगा। यह वर्गों के लिए कुछ बॉयलरप्लेट कोड जोड़ने की आवश्यकता होगी जो आउटपुट होंगे:

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, यह रन-टाइम (जब कॉन्फिग फाइल पढ़ी जाती है) में मेथड कॉल्स की एक श्रृंखला में अनुवादित हो जाती है, इसलिए यह काफी कुशल है। जब तक आपको वास्तव में ज़रूरत न हो, मैं ऐसा करने की सलाह नहीं दूंगा, लेकिन जब आप करते हैं, तो आप कुछ बहुत अच्छा सामान कर सकते हैं।


इन कार्यों से प्यार है जो हमेशा सच होते हैं;) मुझे लगता है कि यह स्थिर init आदेश देने वाले मुद्दों से प्रतिरक्षा है?
पॉलम

14

मैं क्यूटी का उपयोग करने की सलाह दूंगा

एक ओपन-सोर्स लाइसेंस के साथ-साथ एक वाणिज्यिक लाइसेंस भी है।


1
मैंने इसे देखा लेकिन यह मैक्रोज़ का उपयोग करता है और मेटा-डेटा कोड उत्पन्न करने के लिए स्रोत कोड को पार्सिंग की आवश्यकता होती है। मैं इस अतिरिक्त कदम से बचना चाहता हूं। मैं C ++ लाइब्रेरी या साधारण मैक्रोज़ का उपयोग करना पसंद करूंगा। हालांकि विचार के लिए धन्यवाद।
निक

10
क्यूटी, या इसी तरह के दृष्टिकोण को लागू करने वाला एक अन्य पुस्तकालय वह सबसे अच्छा है जिसे आप प्राप्त करने जा रहे हैं
jalf

5
संकलित समय पर भुगतान करें या रनटाइम पर भुगतान करें - या तो आप भुगतान कर रहे हैं!
मार्टिन बेकेट

13

आप प्रतिबिंब के साथ क्या करने की कोशिश कर रहे हैं?
आप बूस्ट प्रकार के लक्षण और टाइप - लाइब्ररी का उपयोग सीमित समय के संकलन के रूप में कर सकते हैं। यही है, आप एक टेम्प्लेट में उत्तीर्ण प्रकार के मूल गुणों का निरीक्षण और संशोधन कर सकते हैं।


13

संपादित करें : CAMP को और अधिक बनाए नहीं रखा गया है; दो कांटे उपलब्ध हैं:

  • एक को CAMP भी कहा जाता है, और एक ही API पर आधारित होता है।
  • पैंडर एक आंशिक पुनर्लेखन है, और इसे प्राथमिकता दी जाएगी क्योंकि इसमें बूस्ट की आवश्यकता नहीं है; यह C ++ 11 का उपयोग कर रहा है।

CAMP एक MIT लाइसेंस प्राप्त पुस्तकालय (पूर्व में LGPL) है जो C ++ भाषा में प्रतिबिंब जोड़ता है। यह संकलन में एक विशिष्ट प्रीप्रोसेसिंग चरण की आवश्यकता नहीं है, लेकिन बाध्यकारी को मैन्युअल रूप से बनाया जाना है।

वर्तमान टेगसॉफ्ट पुस्तकालय बूस्ट का उपयोग करता है, लेकिन एक कांटा भी है सी ++ 11 का उपयोग करने वाला अब बूस्ट की आवश्यकता नहीं है


11

मैंने कुछ ऐसा किया जो आप एक बार के बाद कर रहे हैं, और जबकि कुछ स्तर पर प्रतिबिंब प्राप्त करना और उच्च-स्तरीय सुविधाओं तक पहुंच प्राप्त करना संभव है, रखरखाव सिरदर्द इसके लायक नहीं हो सकता है। मेरा सिस्टम यूआई कक्षाओं को पूरी तरह से व्यापारिक तर्क से अलग रखने के लिए इस्तेमाल किया गया था, जो कि आक्यूपेशन-सी के माध्यम से मेसेज पासिंग और फॉरवर्डिंग की अवधारणा के लिए व्यापारिक तर्क से अलग था। ऐसा करने का तरीका कुछ बेस क्लास बनाना है जो प्रतीकों को मैप करने में सक्षम है (मैंने एक स्ट्रिंग पूल का उपयोग किया है लेकिन आप इसे एंम्स के साथ कर सकते हैं यदि आप गति और संकलन के लिए कुल लचीलेपन से निपटने में त्रुटि) को प्राथमिकता देते हैं (वास्तव में नहीं शुद्ध फंक्शन पॉइंटर्स, लेकिन बूस्ट के साथ बूस्ट.फंक्शन के समान कुछ है - जो कि उस समय मेरे पास नहीं था)। आप अपने सदस्य चर के लिए एक ही काम कर सकते हैं जब तक आपके पास कुछ सामान्य आधार वर्ग है जो किसी भी मूल्य का प्रतिनिधित्व करने में सक्षम है। संपूर्ण प्रणाली की-वैल्यू कोडिंग और डेलिगेशन का एक मानवरहित नियम था, जिसमें कुछ साइड इफेक्ट्स थे जो शायद हर वर्ग को प्राप्त करने के लिए आवश्यक समय की कीमत के बराबर थे जो कि सिस्टम को उसके सभी तरीकों और सदस्यों को कानूनी कॉल के साथ मैच करने के लिए उपयोग करते थे। : 1) कोई भी वर्ग हेडर को शामिल किए बिना किसी भी अन्य वर्ग पर किसी भी विधि को कॉल कर सकता है या नकली आधार कक्षाएं लिख सकता है, ताकि इंटरफ़ेस को कंपाइलर के लिए पूर्वनिर्धारित किया जा सके; और 2) सदस्य चर के गेटर्स और सेटर को धागा-सुरक्षित बनाना आसान था क्योंकि सभी वस्तुओं के आधार वर्ग में उनके तरीकों को बदलते या एक्सेस करना हमेशा 2 तरीकों के माध्यम से किया गया था। संपूर्ण प्रणाली की-वैल्यू कोडिंग और डेलिगेशन का एक मानवरहित नियम था, जिसमें कुछ साइड इफेक्ट्स थे जो शायद हर वर्ग को प्राप्त करने के लिए आवश्यक समय की कीमत के बराबर थे जो कि सिस्टम को उसके सभी तरीकों और सदस्यों को कानूनी कॉल के साथ मैच करने के लिए उपयोग करते थे। : 1) कोई भी वर्ग हेडर को शामिल किए बिना किसी भी अन्य वर्ग पर किसी भी विधि को कॉल कर सकता है या नकली आधार कक्षाएं लिख सकता है, ताकि इंटरफ़ेस को कंपाइलर के लिए पूर्वनिर्धारित किया जा सके; और 2) सदस्य चर के गेटर्स और सेटर को धागा-सुरक्षित बनाना आसान था क्योंकि सभी वस्तुओं के आधार वर्ग में उनके तरीकों को बदलते या एक्सेस करना हमेशा 2 तरीकों के माध्यम से किया गया था। संपूर्ण प्रणाली की-वैल्यू कोडिंग और डेलिगेशन का एक मानवरहित नियम था, जिसमें कुछ साइड इफेक्ट्स थे जो शायद हर वर्ग को प्राप्त करने के लिए आवश्यक समय की कीमत के बराबर थे जो कि सिस्टम को उसके सभी तरीकों और सदस्यों को कानूनी कॉल के साथ मैच करने के लिए उपयोग करते थे। : 1) कोई भी वर्ग हेडर को शामिल किए बिना किसी भी अन्य वर्ग पर किसी भी विधि को कॉल कर सकता है या नकली आधार कक्षाएं लिख सकता है, ताकि इंटरफ़ेस को कंपाइलर के लिए पूर्वनिर्धारित किया जा सके; और 2) सदस्य चर के गेटर्स और सेटर को धागा-सुरक्षित बनाना आसान था क्योंकि सभी वस्तुओं के आधार वर्ग में उनके तरीकों को बदलते या एक्सेस करना हमेशा 2 तरीकों के माध्यम से किया गया था। 1) कोई भी वर्ग हेडर को शामिल किए बिना किसी भी अन्य वर्ग पर किसी भी विधि को कॉल कर सकता है या नकली आधार कक्षाएं लिख सकता है, ताकि इंटरफ़ेस को संकलक के लिए पूर्वनिर्धारित किया जा सके; और 2) सदस्य चर के गेटर्स और सेटर को धागा-सुरक्षित बनाना आसान था क्योंकि सभी वस्तुओं के आधार वर्ग में उनके तरीकों को बदलते या एक्सेस करना हमेशा 2 तरीकों के माध्यम से किया गया था। 1) कोई भी वर्ग हेडर को शामिल किए बिना किसी भी अन्य वर्ग पर किसी भी विधि को कॉल कर सकता है या नकली आधार कक्षाएं लिख सकता है, ताकि इंटरफ़ेस को संकलक के लिए पूर्वनिर्धारित किया जा सके; और 2) सदस्य चर के गेटर्स और सेटर को धागा-सुरक्षित बनाना आसान था क्योंकि सभी वस्तुओं के आधार वर्ग में उनके तरीकों को बदलते या एक्सेस करना हमेशा 2 तरीकों के माध्यम से किया गया था।

इसने कुछ वास्तव में अजीब चीजें करने की संभावना को जन्म दिया, जो अन्यथा सी ++ में आसान नहीं हैं। उदाहरण के लिए, मैं एक एरे ऑब्जेक्ट बना सकता था जिसमें किसी भी प्रकार की मनमानी चीजें शामिल थीं, जिसमें स्वयं भी शामिल हैं, और सभी सरणी वस्तुओं को संदेश पास करके और रिटर्न वैल्यूज़ (लिस्प में मैप के समान) इकट्ठा करके गतिशील रूप से नई सरणियाँ बनाएं। एक अन्य कुंजी-मूल्य का कार्यान्वयन था, जिसके तहत मैं लगातार डेटा को प्रदूषित करने या अनावश्यक रूप से प्रदर्शन को कम करने के बजाय बैकएंड कक्षाओं के सदस्यों में परिवर्तन का तुरंत जवाब देने के लिए यूआई स्थापित करने में सक्षम था।

शायद आपके लिए और अधिक रोचक तथ्य यह है कि आप एक वर्ग के लिए परिभाषित सभी तरीकों और सदस्यों को भी डंप कर सकते हैं, और स्ट्रिंग रूप में कम नहीं।

सिस्टम को डाउनसाइड करना जो आपको परेशान करने से हतोत्साहित कर सकता है: सभी संदेशों और मुख्य-मूल्यों को जोड़ना बेहद थकाऊ है; यह किसी भी प्रतिबिंब के बिना की तुलना में धीमी है; आप देखकर boost::static_pointer_castऔर नफरत करने के लिए विकसित होंगेboost::dynamic_pointer_cast हिंसक जुनून के साथ अपने कोडबस को ; दृढ़ता से टाइप किए गए सिस्टम की सीमाएं अभी भी हैं, आप वास्तव में बस उन्हें थोड़ा छिपा रहे हैं इसलिए यह स्पष्ट नहीं है। अपने तार में टाइपो भी एक मजेदार या आश्चर्य की खोज करने के लिए आसान नहीं हैं।

इस तरह से कुछ को लागू करने के तरीके के रूप में: बस कुछ सामान्य आधार के लिए साझा और कमजोर संकेत का उपयोग करें (मेरा बहुत कल्पनाशील रूप से "ऑब्जेक्ट" कहा जाता था) और उन सभी प्रकारों के लिए प्राप्त करें जिन्हें आप उपयोग करना चाहते हैं। मैं यह करने के बजाय Boost.Function को स्थापित करने की सलाह दूंगा, जिस तरह से मैंने किया, जो कुछ कस्टम बकवास और एक टन बदसूरत मैक्रोज़ के साथ फ़ंक्शन पॉइंटर कॉल को लपेटने के लिए था। चूंकि सब कुछ मैप किया गया है, वस्तुओं का निरीक्षण करना सभी चाबियों के माध्यम से पुनरावृत्ति करना है। चूँकि मेरी कक्षाएं अनिवार्य रूप से केवल C ++ का उपयोग करते हुए कोको के एक प्रत्यक्ष ripoff के करीब थीं, अगर आप ऐसा कुछ चाहते हैं, तो मैं एक ब्लूप्रिंट के रूप में कोको प्रलेखन का उपयोग करने का सुझाव दूंगा।


अरे, @ मिचेल; क्या आपके पास अभी भी इसके लिए स्रोत कोड है, या क्या आपने इससे छुटकारा पा लिया है? अगर आपको कोई आपत्ति नहीं है तो मैं इस पर एक नज़र रखना चाहता हूं।
रैंडमडेसडेवल

वूप्स, आपका नाम गलत लिखा गया है! कोई आश्चर्य नहीं कि मुझे कभी कोई उत्तर नहीं मिला ...
randomDSdevel

10

वहाँ सी में प्रतिबिंब के लिए एक और नया पुस्तकालय ++, कहा जाता है RTTR (भागो समय प्रकार प्रतिबिंब, यह भी देखें GitHub )।

इंटरफ़ेस C # में प्रतिबिंब के समान है और यह किसी भी RTTI के बिना काम करता है।


8

मेरे C ++ दिनों के दो प्रतिबिंब जैसे समाधान मुझे पता हैं:

1) आरटीटीआई का उपयोग करें, जो आपके प्रतिबिंब-जैसा व्यवहार बनाने के लिए आपके लिए एक बूटस्ट्रैप प्रदान करेगा, यदि आप अपने सभी वर्गों को एक 'ऑब्जेक्ट' बेस क्लास से प्राप्त करने में सक्षम हैं। वह वर्ग कुछ तरीके प्रदान कर सकता है जैसे GetMethod, GetBaseClass आदि। उन तरीकों से काम करने के लिए आपको अपने प्रकारों को सजाने के लिए मैन्युअल रूप से कुछ मैक्रो जोड़ने की आवश्यकता होगी, जो कि पर्दे के पीछे गेटमैथ्स आदि के उत्तर प्रदान करने के लिए मेटाडेटा बनाते हैं।

2) एक अन्य विकल्प, यदि आपके पास संकलक वस्तुओं तक पहुंच है, तो डीआईए एसडीके का उपयोग करना है । अगर मुझे सही से याद है तो यह आपको pdbs खोलने देता है, जिसमें आपके C ++ प्रकारों के लिए मेटाडेटा होना चाहिए। यह वह करने के लिए पर्याप्त हो सकता है जिसकी आपको आवश्यकता है। यह पृष्ठ दिखाता है कि आप सभी प्रकार के वर्ग को उदाहरण के लिए कैसे प्राप्त कर सकते हैं।

इन दोनों समाधान हालांकि थोड़ा बदसूरत हैं! आपको C # की विलासिता की सराहना करने के लिए C ++ की तरह कुछ भी नहीं है।

शुभ लाभ।


यह चालाक और एक विशाल हैक है, डीआईए एसडीके चीज़ के साथ जो आपने वहां सुझाया था।
स्केकी

7

EDIT: फरवरी, 7, 2017 तक टूटी हुई लिंक अपडेट की गई।

मुझे लगता है कि किसी ने इसका उल्लेख नहीं किया है:

CERN में वे C ++ के लिए पूर्ण परावर्तन प्रणाली का उपयोग करते हैं:

सर्न पलटा । यह बहुत अच्छी तरह से काम करने लगता है।


@ j4nbur53 लिंक टूट गया है क्योंकि यह लगता है कि वे एक मील का पत्थर तक पहुँच: root.cern.ch
Germán Diago

क्या यह हो सकता है कि आप इस लिंक root.cern.ch/root/doc/ROOTUsersGuideHTML/ch07.html अध्याय प्रतिवर्त का अर्थ निकाल सकते हैं ?
मोस्टकोस्की

इस रूट की कोशिश करें । cern.ch/how/how-use-reflex रिफ्लेक्स एक जनरेटर के रूप में काम करता है जो आपकी हेडर फ़ाइलों को पार्स करता है और c ++ इंट्रोस्पेक्शन कोड / लाइब्रेरी उत्पन्न करता है, जिसे आप लिंक कर सकते हैं और एक साधारण एपीआई का उपयोग कर सकते हैं।
एडम रिक्ज़ोस्की 15

6

यह प्रश्न अब थोड़ा पुराना है (न जाने क्यों मैं आज पुराने प्रश्नों को दबाए रखता हूं) लेकिन मैं BOOST_FUSION_ADAPT_STRUCT के बारे में सोच रहा था जो संकलन-समय के प्रतिबिंब का परिचय देता है।

यह आप पर निर्भर है कि आप रन-टाइम रिफ्लेक्शन के लिए इसे मैप करें, और यह बहुत आसान नहीं होगा, लेकिन यह इस दिशा में संभव है, जबकि यह रिवर्स में नहीं होगा :)

मुझे लगता है कि एक मैक्रो को एनकैप्सुलेट BOOST_FUSION_ADAPT_STRUCTकरना चाहिए जो रनटाइम व्यवहार प्राप्त करने के लिए आवश्यक तरीके उत्पन्न कर सकता है।


2
द्वारा मिंगहुआ (जिन्होंने मूल रूप से पोस्ट को संपादित किया): मैंने इस BOOST_FUSION_ADAPT_STRUCT समाधान में खोदा और आखिरकार एक उदाहरण के साथ आया। इस नए SO प्रश्न को देखें - C ++ नेचर को नेस्टेड स्ट्रक्चर फील्ड में बूस्ट फ्यूजन adapt_struct के साथ
Matthieu M.

महान, मैथ्यू! बस एहसास हुआ कि पिछले साल के दौरान यहां और वहां आपके संकेत देखे गए हैं। ध्यान नहीं दिया कि वे अब तक संबंधित हैं। वे बहुत प्रेरणादायक थे।
मिंगुआ

6

मुझे लगता है कि आपको डोमिनिक फिलियन द्वारा "सी में चिंतन के लिए टेम्पलेट्स का उपयोग करना" लेख दिलचस्प लग सकता है। यह गेम प्रोग्रामिंग 5 के खंड 1.4 में है । दुर्भाग्य से मेरे पास मेरी प्रति नहीं है, लेकिन इसे देखें क्योंकि मुझे लगता है कि यह बताता है कि आप क्या पूछ रहे हैं।


4

पंडर इस सवाल के जवाब में एक C ++ प्रतिबिंब पुस्तकालय है। मैंने विकल्पों पर विचार किया और अपना खुद का बनाने का फैसला किया क्योंकि मैं अपने सभी बक्से को टिक नहीं पाया।

यद्यपि इस प्रश्न के महान उत्तर हैं, मैं टन मैक्रो का उपयोग नहीं करना चाहता हूं, या बूस्ट पर भरोसा करना चाहता हूं। बूस्ट एक बेहतरीन लाइब्रेरी है, लेकिन बहुत से छोटे बीस्पोक सी ++ 0x प्रोजेक्ट हैं जो सरल हैं और तेजी से संकलन समय हैं। एक वर्ग को बाहरी रूप से सजाने में सक्षम होने के भी फायदे हैं, जैसे कि C ++ लाइब्रेरी को लपेटना जो C ++ 11 का समर्थन नहीं करता (अभी तक?)। सीएपी 11 का उपयोग करते हुए, यह सीएएमपी का कांटा है, जिसे अब बूस्ट की आवश्यकता नहीं है


4

परावर्तन अनिवार्य रूप से इस बारे में है कि संकलक ने कोड में पैरों के निशान के रूप में छोड़ने का फैसला किया जो रनटाइम कोड क्वेरी कर सकता है। C ++ आपके द्वारा उपयोग नहीं किए जाने के लिए भुगतान नहीं करने के लिए प्रसिद्ध है; क्योंकि अधिकांश लोग प्रतिबिंब का उपयोग नहीं करना चाहते / चाहती हैं, C ++ कंपाइलर कुछ भी रिकॉर्ड न करके लागत से बचता है

इसलिए, C ++ प्रतिबिंब प्रदान नहीं करता है, और यह सामान्य नियम के रूप में खुद को "अनुकरण" करना आसान नहीं है क्योंकि अन्य उत्तर नोट किए गए हैं।

"अन्य तकनीकों" के तहत, यदि आपके पास प्रतिबिंब वाली भाषा नहीं है, तो एक उपकरण प्राप्त करें जो संकलन समय पर आपके द्वारा वांछित जानकारी निकाल सकता है।

हमारे डीएमएस सॉफ्टवेयर रीइंजीनियरिंग टूलकिट सामान्यकृत संकलक प्रौद्योगिकी है जिसे स्पष्ट लैंग्वेज परिभाषाओं द्वारा मानकीकृत किया गया है। यह C, C ++, Java, COBOL, PHP, ...

सी, सी ++, जावा और कोबोल संस्करणों के लिए, यह पार्स पेड़ों, और प्रतीक तालिका जानकारी तक पूरी पहुंच प्रदान करता है। उस प्रतीक तालिका जानकारी में उस प्रकार का डेटा शामिल है जिसे आप "प्रतिबिंब" से चाहते हैं। यदि आप लक्ष्य फ़ील्ड या विधियों के कुछ सेट की गणना करना और उनके साथ कुछ करना चाहते हैं, तो डीएमएस का उपयोग कोड को बदलने के लिए किया जा सकता है जो आपको मनमाने तरीके से प्रतीक तालिकाओं में मिलता है।


3

आप यहां एक और पुस्तकालय पा सकते हैं: http://www.garret.ru/cppreflection/docs/reflect.html यह 2 तरीकों का समर्थन करता है: डिबग जानकारी से प्रकार की जानकारी प्राप्त करना और प्रोग्रामर को यह जानकारी प्रदान करना।

मैंने अपनी परियोजना के लिए प्रतिबिंब बनाने में भी दिलचस्पी ली और इस पुस्तकालय को पाया, मैंने अभी तक इसकी कोशिश नहीं की है, लेकिन इस आदमी से अन्य उपकरणों की कोशिश की और मुझे पसंद है कि मैं कैसे काम करता हूं :-)


3

Classdesc http://classdesc.sf.net देखें । यह क्लास "डिस्क्रिप्टर" के रूप में प्रतिबिंब प्रदान करता है, किसी भी मानक C ++ कंपाइलर (हाँ यह विजुअल स्टूडियो के साथ-साथ GCC के साथ काम करने के लिए जाना जाता है) के साथ काम करता है, और इसे स्रोत कोड एनोटेशन की आवश्यकता नहीं होती है (हालांकि कुछ प्रांगण मुश्किल परिस्थितियों को संभालने के लिए मौजूद हैं। )। यह एक दशक से अधिक समय से विकास में है, और कई औद्योगिक पैमाने की परियोजनाओं में उपयोग किया जाता है।


1
ढेर अतिप्रवाह में आपका स्वागत है। यद्यपि यह उत्तर विषय पर है, यह इंगित करना महत्वपूर्ण है कि आप इस सॉफ़्टवेयर के लेखक हैं, यह स्पष्ट करने के लिए कि यह एक निष्पक्ष सिफारिश नहीं है :-)
मैथ्यू स्ट्रॉब्रिज

2

जब मुझे C ++ में प्रतिबिंब चाहिए था तो मैंने इस लेख को पढ़ा और मैंने जो देखा, उसमें सुधार किया। क्षमा करें, नहीं हो सकता है। मेरे पास परिणाम नहीं है ... लेकिन आप निश्चित रूप से वही कर सकते हैं जो मेरे पास था और मैं वहां से जा रहा था।

मैं वर्तमान में शोध कर रहा हूं, जब मुझे ऐसा लगता है, तो प्रतिबिंबित करने योग्य प्रकारों की परिभाषा को अधिक आसान बनाने के लिए तरीके का उपयोग करना। मैं वास्तव में काफी दूर हो गया हूं, लेकिन मेरे पास अभी भी एक रास्ता है। C ++ 0x में परिवर्तन से इस क्षेत्र में बहुत मदद मिलने की संभावना है।


2

ऐसा लगता है कि C ++ में अभी भी यह सुविधा नहीं है। और C ++ 11 परावर्तन भी (

कुछ मैक्रोज़ खोजें या स्वयं बनाएं। क्यूटी भी प्रतिबिंब के साथ मदद कर सकता है (यदि इसका उपयोग किया जा सकता है)।


2

भले ही प्रतिबिंब c ++ में आउट-ऑफ-द-बॉक्स समर्थित नहीं है, लेकिन इसे लागू करना बहुत कठिन नहीं है। मैंने इस महान लेख का सामना किया है: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html

लेख बहुत विस्तार से बताता है कि आप एक बहुत सरल और अल्पविकसित प्रतिबिंब प्रणाली कैसे लागू कर सकते हैं। इसका सबसे अच्छा समाधान नहीं दिया गया है, और छंटे हुए किनारों को छांटना बाकी है, लेकिन मेरी जरूरतों के लिए यह पर्याप्त था।

नीचे पंक्ति - प्रतिबिंब सही ढंग से किए जाने पर भुगतान कर सकता है, और यह c ++ में पूरी तरह से संभव है।


2

मैं स्वत: आत्मनिरीक्षण / प्रतिबिंब टूलकिट "आईडीके" के अस्तित्व का विज्ञापन करना चाहूंगा। यह 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/TestCppetefef/

मैं इसे स्पष्टीकरण के साथ आंशिक रूप से कॉपी करूंगा:

#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 );

}

REFLECTABLEपरिभाषित करता है कि वर्ग नाम + फ़ील्ड नाम का उपयोग offsetofकिस मेमोरी विशेष क्षेत्र में स्थित है। मैंने जहाँ तक संभव हो .NET शब्दावली को लेने की कोशिश की है, लेकिन C ++ और C # अलग-अलग हैं, इसलिए यह 1 से 1. नहीं है। संपूर्ण C ++ प्रतिबिंब मॉडल अंदर TypeInfoऔर FieldInfoकक्षाओं में रहता है ।

मैंने pugi xml parser का उपयोग 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>

किसी भी 3-rd पार्टी वर्ग / संरचना समर्थन को टाइपट्रैट्स क्लास और आंशिक टेम्पलेट विनिर्देश के माध्यम से सक्षम करना संभव है - CSTring या int के समान तरीके से अपने स्वयं के टाइपट्रैट्स क्लास को परिभाषित करने के लिए - उदाहरण कोड देखें

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

यह समाधान विंडोज / विजुअल स्टूडियो के लिए लागू है। इसे अन्य 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 एक मैक्रो है, जिसे बाद में वर्णित किया गया है (अद्यतन):

मान लें कि हमने int और std :: string के लिए serialization फंक्शन को परिभाषित किया है:

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 "सरल" प्रकार लागू करने होंगे।

इस मैक्रो में रन-टाइम में स्ट्रक्चर निर्माण / विनाश के लिए शून्य-ओवरहेड होना चाहिए, और 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_DEFINE_STRUCT के साथ संरचनाओं के लिए शांत स्थिर प्रतिबिंब सुविधाएँ प्राप्त कर सकते हैं ।
हाना काफी वर्सटाइल है, न केवल आपके लिए बल्कि हमारे पास जो खाका है, उसके लिए बहुत सारे टेम्प्लेट मेटाप्रोग्रामिंग हैं।


1

रैंडम एक्सेस प्रतिबिंब सभी क्षेत्र / प्रकार की जानकारी के लिए या तो सरणियों में उपलब्ध हो या सरणी पहुँच की तरह महसूस करने डिज़ाइन किया गया है - पुस्तकालय काफी आसान और सहज ज्ञान युक्त प्रतिबिंब के लिए बनाता है। यह C ++ 17 के लिए लिखा गया है और विज़ुअल स्टूडियो, g ++ और क्लैंग के साथ काम करता है। लाइब्रेरी केवल हेडर है, जिसका उपयोग करने के लिए आपको अपनी परियोजना में केवल "Reflect.h" कॉपी करना होगा।

परावर्तित संरचनाओं या वर्गों को आवश्यक मैक्रो की आवश्यकता होती है, जहां आप उस वर्ग के नाम की आपूर्ति करते हैं जिसे आप प्रतिबिंबित कर रहे हैं और खेतों के नाम।

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 लाइब्रेरी रैंडमऐसेफ्रीलेक्शन के शीर्ष पर बनाई गई है जो ऑटो पढ़ने या लिखने के लिए उपयुक्त 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);

आप उस फ़ंक्शन को मेमोरी में एक जगह इस तरह से असाइन कर सकते हैं (आवश्यकता libdlऔर dlopen)

#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()में libdl, और dlfcn.h) फ़ंक्शन के तर्कों और प्रकार को जानना है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.