2012-12-12 12 views
8

में समय प्रतिबिंब मैं एक निम्न struct है:अनुकरण संकलन सी ++

struct Data 
{ 
    std::string firstMember; 
    std::string secondMember; 
    std::string thirdMember; 
}; 

मैं constexpr ढंग से स्ट्रिंग नाम से सदस्यों में से एक का चयन करना चाहते,

तरह
Data instance; 
auto& member = getMember(instance, "firstMember"); 

getMember है constexpr समारोह/संरचना/मैक्रोज़/जो कुछ भी प्रश्न और अभिव्यक्ति में होना चाहिए (मैं इसे होना चाहता हूं) सरल auto& member = instance.firstMember; में अनुकूलित किया जाना चाहिए। मेरी इच्छा है कि फ़ंक्शन से getMember पर कॉल करने में सक्षम होना चाहिए, जो बदले में विशेष सदस्य -> ​​किसी प्रकार का संकलन समय प्रतिबिंब का कंप्यूटिंग नाम है।

मुझे पता है, वहाँ सी ++ में कोई प्रतिबिंब है, इसलिए यह किसी भी तरह रजिस्टर करने के लिए (आंशिक रूप से विशेषज्ञ का उपयोग कुछ मैक्रो जादू?) प्रश्न में struct के सदस्यों के नाम, जैसे ठीक है:

REGISTER_MEMBER(Data, "firstMember", firstMember); 

सभी मैं चाहता हूँ उस संकलन समय अनुकूलन है और रनटाइम में कुछ भी नहीं है। क्या यह सी ++ 11 में और कैसे संभव है?

+2

शायद [boost :: fusion] (http://www.boost.org/doc/libs/1_52_0/libs/fusion/doc/html/index.html) यहां सहायता कर सकता है? –

+0

@AlexandreC।, क्या आप कृपया अधिक विशिष्ट हो सकते हैं? बूस्ट :: फ़्यूज़न एक बड़ी लाइब्रेरी है :) इसके अलावा, मैं दोहराना चाहता हूं, मैं कोई रनटाइम ओवरहेड नहीं चाहता हूं, केवल समय गणना संकलित करें। –

+0

@ नफरत इंजन: 'BOOST_FUSION_ADAPT_STRUCT' देखें, जो प्रभावी रूप से आप कोडिंग कर रहे हैं। – GManNickG

उत्तर

13

टिप्पणी में बताया गया है, पहली बार में BOOST_FUSION_ADAPT_STRUCT (और दोस्तों) एक बार देख ले:

#include <boost/fusion/include/at_c.hpp> 

int main() 
{ 
    Data d = { "firstData", "secondData", "thirdData" }; 

    std::cout << boost::fusion::at_c<0>(d) << std::endl; 
} 

यह प्रिंट "firstData":

#include <boost/fusion/include/adapt_struct.hpp> 
#include <string> 

struct Data 
{ 
    std::string firstMember; 
    std::string secondMember; 
    std::string thirdMember; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    Data, 
    (std::string, firstMember) 
    (std::string, secondMember) 
    (std::string, thirdMember) 
    ) 

यह एक दृश्य फ्यूजन द्वारा प्रयोग करने योग्य में अपने Data संरचना बदल जाता है । क्रम में सदस्यों को संदर्भित करने के लिए सूचकांक बदलें।

वहां, अब हम संख्याओं का उपयोग करके संकलन-समय पर सदस्यों का उल्लेख कर सकते हैं। लेकिन आप एक नाम चाहते थे। टिप्पणियों में भी ध्यान दिया गया है, प्रसंस्करण तार एक रनटाइम सुविधा है ... लगभग। सी ++ 11 हमें constexpr देता है।

यह थोड़ा मुश्किल है, लेकिन अंत में यह इस तरह दिखता है:

#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/preprocessor/cat.hpp> 
#include <boost/preprocessor/repetition/repeat.hpp> 
#include <boost/preprocessor/seq.hpp> 
#include <boost/preprocessor/tuple/elem.hpp> 
#include <stdexcept> 

// and repeat for BOOST_FUSION_ADAPT_TPL_STRUCT, etc... 
#define REFLECT_STRUCT(NAME, ATTRIBUTES)            \ 
     REFLECT_STRUCT_DETAIL(NAME,              \ 
           ATTRIBUTES,            \ 
           BOOST_PP_SEQ_POP_FRONT(         \ 
           BOOST_PP_CAT(           \ 
            /* warning: uses fusion implementation details: */ \ 
            BOOST_FUSION_ADAPT_STRUCT_FILLER_0(0,0)ATTRIBUTES, \ 
            _END)))            \ 

#define REFLECT_STRUCT_DETAIL(NAME, ATTRIBUTES, WRAPPEDATTRIBUTES)     \ 
     BOOST_FUSION_ADAPT_STRUCT(NAME, ATTRIBUTES)         \ 
                        \ 
     namespace detail               \ 
     {                   \ 
      namespace BOOST_PP_CAT(reflect_, NAME)         \ 
      {                  \ 
       template <int N>             \ 
       struct member_name;             \ 
                        \ 
       BOOST_PP_SEQ_FOR_EACH_I(REFLECT_STRUCT_DETAIL_MEMBER_NAME,   \ 
             BOOST_PP_EMPTY,        \ 
             WRAPPEDATTRIBUTES)       \ 
                        \ 
       template <int N>             \ 
       constexpr bool member_match_index(const std::size_t index,   \ 
                const char* const str,   \ 
                const std::size_t len)   \ 
       {                 \ 
        return index == len ||           \ 
          (member_name<N>::value()[index] == str[index]   \ 
          && member_match_index<N>(index + 1, str, len));   \ 
       }                 \ 
                        \ 
       template <int N>             \ 
       constexpr bool member_match(const char* const str,     \ 
              const std::size_t len)     \ 
       {                 \ 
        return len == member_name<N>::value_length      \ 
          && member_match_index<N>(0, str, len);     \ 
       }                 \ 
                        \ 
       constexpr int find_member(const char* const str,     \ 
              const std::size_t len)     \ 
       {                 \ 
        return BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(WRAPPEDATTRIBUTES), \ 
              REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST, \ 
              BOOST_PP_EMPTY)       \ 
          throw std::runtime_error("could not find "    \ 
                BOOST_PP_STRINGIZE(NAME)  \ 
                " member");      \ 
       }                 \ 
      }                  \ 
     }                   \ 
                        \ 
     constexpr int BOOST_PP_CAT(indexof_, NAME)(const char* const str,   \ 
                const std::size_t len)   \ 
     {                   \ 
      return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(str, len);  \ 
     }                   \ 
                        \ 
     template <std::size_t N>             \ 
     constexpr int BOOST_PP_CAT(indexof_, NAME)(const char (&str)[N])   \ 
     {                   \ 
      return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(&str[0], N); \ 
     } 

#define REFLECT_STRUCT_DETAIL_EXTRACT_NAME(pair) \ 
     BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, pair)) 

#define REFLECT_STRUCT_DETAIL_MEMBER_NAME(r, data, n, elem) \ 
     REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, REFLECT_STRUCT_DETAIL_EXTRACT_NAME(elem)) 

#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, name)    \ 
     template <>              \ 
     struct member_name<n>           \ 
     {                \ 
      static constexpr std::size_t value_length = sizeof(name); \ 
      typedef const char value_type[value_length];    \ 
                     \ 
      static constexpr const value_type& value()     \ 
      {               \ 
       return name;           \ 
      }               \ 
     }; 

#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST(z, n, text) \ 
     member_match<n>(str, len) ? n : 

यह डरावना लग रहा है, लेकिन इसके पठनीय अगर आप इसे अलग लेने के लिए समय लगता है।

हमें सदस्यों के नामों को निरंतर अभिव्यक्ति पहुंच प्रदान करने के लिए अपने स्वयं के मैक्रोज़ पेश करना होगा; अधिकांश बदसूरत Boost.Preprocessor सूचियों से प्रसंस्करण से आता है। यद्यपि फ़्यूज़न अनुकूलन के दौरान नामों को रिकॉर्ड करता है (boost::fusion::extension::struct_member_name देखें), उन्हें constexpr के रूप में चिह्नित नहीं किया गया है, इसलिए दुर्भाग्यवश हमारे लिए उपयोग योग्य नहीं हैं।

यह देता है:

#include <boost/fusion/include/at_c.hpp> 
#include <iostream> 
#include <string> 

struct Data 
{ 
    std::string firstMember; 
    std::string secondMember; 
    std::string thirdMember; 
}; 

REFLECT_STRUCT(
    Data, 
    (std::string, firstMember) 
    (std::string, secondMember) 
    (std::string, thirdMember) 
    ) 

// your desired code: 
// (note the use of at_c ensures this is evaluated at comple-time) 
#define GETMEMBER(data, member) boost::fusion::at_c<indexof_Data(member)>(data) 

int main() 
{ 
    Data d = { "firstData", "secondData", "thirdData" }; 

    std::cout << boost::fusion::at_c<indexof_Data("firstMember")>(d) << std::endl; 
    std::cout << GETMEMBER(d, "secondMember") << std::endl; 
    std::cout << GETMEMBER(d, "thirdMember") << std::endl; 
    /* causes error: std::cout << GETMEMBER(d, "nonexistent_member") << std::endl; */ 
} 

कौन सा मुझे लगता है कि क्या आप के बाद कर रहे थे के करीब है।

लेकिन ध्यान रखें कि यह आवश्यक नहीं हो सकता है: बूस्ट.फ्यूजन में पहले से ही आपकी आवश्यकता हो सकती है। यह शुद्ध संकलन-समय सामग्री (बूस्ट.एमपीएल) और नियमित रन-टाइम सामान के बीच के क्षेत्र में रहता है; अपनी संरचना को अनुकूलित करें और आप पहले से ही इस तरह की चीजें कर सकते हैं (boost::fusion::for_each)।

+0

बिल्कुल सही! आपका बहुत बहुत धन्यवाद! –

संबंधित मुद्दे