2012-12-12 13 views
8

に時間反射をコンパイルシミュレート構造体/マクロ/問題の式は、単純にauto& member = instance.firstMember;に最適化する必要があります。私の望みは、getMemberを別のconstexpr関数から呼び出すことです。この関数は、特定のメンバの名前を計算しています - >ある種のコンパイル時の反映です。は、私は、次の構造体を持つC++

私が知っている、C++には反射は、したがって、それは何らかの形で登録してOKですが、存在しない問題の構造体のメンバーの名前、などの(部分的に特化し、いくつかのマクロの魔法を使う?):

REGISTER_MEMBER(Data, "firstMember", firstMember); 

私が欲しいのコンパイル時の最適化を行い、実行時に何もしないことです。それはC++ 11で可能ですか?コメントで述べたように

+2

多分[boost :: fusion](http://www.boost.org/doc/libs/1_52_0/libs/fusion/doc/html/index.html)はここで助けになるでしょうか? –

+0

@AlexandreC。、より具体的にお願いしますか? Boost :: fusionは大きなライブラリです:)また、私は繰り返し言いたいのですが、私はランタイムオーバーヘッドを必要とせず、時間計算だけをコンパイルします。 –

+0

@ hate-engine:効果的にコーディングしている 'BOOST_FUSION_ADAPT_STRUCT'を参照してください。 – GManNickG

答えて

13

、最初BOOST_FUSION_ADAPT_STRUCT(や友人)を見てみましょう:

#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構造を回す:

#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"を印刷します。メンバを順番に参照するようにインデックスを変更します。

ここで、メンバーをコンパイル時に番号で参照できます。しかし、あなたは名前がほしいと思った。コメントにも注意しておきますが、処理文字列はランタイム機能です。 C++ 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は、必要なものをすでに持っているかもしれません。純粋なコンパイル時のもの(Boost.MPL)と通常の実行時のものとの間の領域に存在します。あなたの構造体を適応させ、それを反復するようなことを既に行うことができます(boost::fusion::for_each)。

+0

パーフェクト!どうもありがとうございました! –

関連する問題