2017-08-05 5 views
1

私はある種の "データ変数"フレームワークに取り組んでいます。ここでは、構造体はBoost.FusionシーケンスとしてマクロBOOST_FUSION_DEFINE_ASSOC_STRUCTを使って定義され、適合されています。Variadicマクロ:可変引数を再利用する(Boost.Fusion)

ブリーフコンテキスト:

私が使用する2つの適応構造体foobarを定義するには:

#define VAR(VARNAME) vardefs::VARNAME 
#define VAR_PARENTHESES(VARNAME) (vardefs)(VARNAME) 

// ======================================================== 
#ifndef VARNAME_ 
#define VARNAME_ foo // <- Variable name 
namespace VAR(VARNAME_)::keys{ 
    struct foo1; 
    struct foo2; 
    struct foo3; 
} 
namespace VAR(VARNAME_) { struct index; } 

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
    VAR_PARENTHESES(VARNAME_), type, 
    (char, foo1, VAR(VARNAME_)::keys::foo1) 
    (int, foo2, VAR(VARNAME_)::keys::foo2) 
    (float, foo3, VAR(VARNAME_)::keys::foo3) 
) 
#endif 
#undef VARNAME_ 
// -------------------------------------------------------- 

// ======================================================== 
#ifndef VARNAME_ 
#define VARNAME_ bar // <- Variable name 
namespace VAR(VARNAME_)::keys{ 
    struct bar1; 
    struct bar2; 
} 
namespace VAR(VARNAME_) { struct index; } 

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
    VAR_PARENTHESES(VARNAME_), type, 
    (double, bar1, VAR(VARNAME_)::keys::bar1) 
    (float, bar2, VAR(VARNAME_)::keys::bar2) 
) 
#endif 
#undef VARNAME_ 
// -------------------------------------------------------- 

今1を使用してfoobarのインスタンスを作成することができます

VAR(foo)::type fooI; 
VAR(bar)::type barI; 

連想キーはこのように使用できます:

auto a = boost::fusion::at_key<VAR(foo)::keys::foo3>(fooI). 
auto b = boost::fusion::at_key<VAR(bar)::keys::bar2>(barI). 

このアプローチは、行の下で便利です。

最後に、構造体そのもののタグがあります。

VAR(bar)::index 
VAR(foo)::index 

私は、例えば、他のBoost.Fusion配列において型キーとして以降を使用することができますboost::fusion::map

質問:私は連想シーケンスを定義していますので、2つの構造体のそれぞれのために、そして、私は構造体フィールド名を使用する必要があり、

お知らせ(foo1bar2を、...)3毎回。私が代わりに希望は何

は、このよう上記の二つの構造体を定義することです:

// ======================================================== 
DEFINE_DATAVAR_STRUCT(
    foo, 
    (char, foo1) 
    (int, foo2) 
    (float, foo3) 
) 
// -------------------------------------------------------- 

// ======================================================== 
DEFINE_DATAVAR_STRUCT(
    bar, 
    (double, bar1) 
    (float, bar2) 
) 
// -------------------------------------------------------- 

私は可変引数マクロDEFINE_DATAVAR_STRUCTを定義する必要があります。これは私が助けが必要なものです。私にとっての問題は、生成されたコード内の複数の場所に表示できるように、可変引数を再利用することです。どういうわけか、Boost.Fusionは何とか(Boost.PPに依存して)問題なくこれをやっています。

私自身の研究:

私はBoost.PPライブラリを見てきましたが、私はここに非常に良い進歩を致しておりません。 Boost.Fusionライブラリは既にこれを行っているので、BOOST_FUSION_DEFINE_ASSOC_STRUCTマクロに似た、同じバリデーション機能を実現する方法が必要です。

Boost.FusionマクロBOOST_FUSION_DEFINE_ASSOC_STRUCTは、.../define_assoc_struct.hppの40〜50行目に定義されています。これらのマクロを構築する魔法の多くは、.../define_struct.hpp(特に413行目のマクロBOOST_FUSION_DEFINE_STRUCT_IMPL)にあります。このファイルはBoost.PPを多く利用しています。

コンパイラ: Microsoft Visual Studio 2015 Update 3(GCC、Clangは現在オプションではありません)。

ブースト: 1.64.0。名前(bar)と「シーケンス」:あなたは二つの引数を持っている。このマクロで

DEFINE_DATAVAR_STRUCT(
    bar, 
    (double, bar1) 
    (float, bar2) 
) 

+0

Iは、単にコードを生成するだろう。この問題を解決することによって引き起こされる以下の例で既存のBOOST_FUSION_DEFINE_STRUCTマクロを改造する(コピーして、代わりに欲しいコードを発行する) – sehe

+0

これは素晴らしいアイデアです。実際に私が実際に念頭に置いていたことですが、私の問題は '__VA_ARGS__'を利用して、 Boost.Fusionマクロとしてのバリデーショナルな振る舞い。おそらく私はBoost.Fusionの実装をコピーするだけかもしれません。私は少し質問を更新します。 –

答えて

1

お好みのマクロの呼び出しからすべてのあなたの定型を生成するマクロを作成することは比較的容易ですタプルの数((double,bar1)(float,bar2))。 Boost.Preprocessorマクロで動作するタプルのシーケンスを得るためには、2組のかっこで区切られた各タプルを持つ必要があるので、 "シーケンス"を引用符で囲みます。複雑さのほとんどが(この詳細については、this answerにアプローチ3である。


Running on Wandbox

#include <iostream> 
#include <boost/preprocessor/seq/for_each.hpp> 
#include <boost/preprocessor/tuple/elem.hpp> 
#include <boost/preprocessor/cat.hpp> 
#include <boost/fusion/include/define_assoc_struct.hpp> 
#include <boost/fusion/include/at_key.hpp> 



#define VAR(VARNAME) vardefs::VARNAME 
#define VAR_PARENTHESES(VARNAME) (vardefs)(VARNAME) 

//THIS IS ONLY NEEDED IN ORDER TO GET 2 SETS OF PARENTHESES 
//Heavily "inspired" from BOOST_FUSION_ADAPT_STRUCT 
#define GENERATE_DATAVAR_SEQUENCE_FILLER_0(X, Y) \ 
    ((X, Y)) GENERATE_DATAVAR_SEQUENCE_FILLER_1 
#define GENERATE_DATAVAR_SEQUENCE_FILLER_1(X, Y) \ 
    ((X, Y)) GENERATE_DATAVAR_SEQUENCE_FILLER_0 
#define GENERATE_DATAVAR_SEQUENCE_FILLER_0_END 
#define GENERATE_DATAVAR_SEQUENCE_FILLER_1_END 

#define GENERATE_DATAVAR_SEQUENCE(MEMBERS) BOOST_PP_CAT(GENERATE_DATAVAR_SEQUENCE_FILLER_0 MEMBERS,_END) 

//THESE AREN'T ACTUALLY REQUIRED BUT HELP WITH READABILITY 
#define DATAVAR_GET_TYPE(TUPLE) BOOST_PP_TUPLE_ELEM(2,0,TUPLE) 
#define DATAVAR_GET_NAME(TUPLE) BOOST_PP_TUPLE_ELEM(2,1,TUPLE) 

//THESE ARE THE HELPERS THAT ACTUALLY GENERATE THE VARIABLE PARTS OF THE MACRO 
#define GENERATE_STRUCT_KEYS(_,__,TUPLE) struct DATAVAR_GET_NAME(TUPLE); 
#define GENERATE_STRUCT_DEFINITION_SEQ(_,NAME,TUPLE) (DATAVAR_GET_TYPE(TUPLE),DATAVAR_GET_NAME(TUPLE),VAR(NAME)::keys::DATAVAR_GET_NAME(TUPLE)) 

// =============================================================================================== 
#define DEFINE_DATAVAR_STRUCT(NAME,MEMBERS)              \ 
namespace VAR(NAME)::keys{                  \ 
    BOOST_PP_SEQ_FOR_EACH(GENERATE_STRUCT_KEYS,_,GENERATE_DATAVAR_SEQUENCE(MEMBERS))    \ 
}                        \ 
namespace VAR(NAME) { struct index; }               \ 
BOOST_FUSION_DEFINE_ASSOC_STRUCT(                \ 
    VAR_PARENTHESES(NAME), type,                 \ 
    BOOST_PP_SEQ_FOR_EACH(GENERATE_STRUCT_DEFINITION_SEQ,NAME,GENERATE_DATAVAR_SEQUENCE(MEMBERS))\ 
) 
// ----------------------------------------------------------------------------------------------- 


// ======================================================== 
DEFINE_DATAVAR_STRUCT(
    foo, 
    (char, foo1) 
    (int, foo2) 
    (float, foo3) 
) 
// -------------------------------------------------------- 

// ======================================================== 
DEFINE_DATAVAR_STRUCT(
    bar, 
    (double, bar1) 
    (float, bar2) 
) 
// -------------------------------------------------------- 


int main() 
{ 
    VAR(foo)::type fooI{'a',1,2.0f}; 
    VAR(bar)::type barI{1.0,2.0f}; 

    std::cout << boost::fusion::at_key<VAR(foo)::keys::foo1>(fooI) << std::endl; 
    std::cout << boost::fusion::at_key<VAR(foo)::keys::foo2>(fooI) << std::endl; 
    std::cout << boost::fusion::at_key<VAR(foo)::keys::foo3>(fooI) << std::endl; 
    std::cout << boost::fusion::at_key<VAR(bar)::keys::bar1>(barI) << std::endl; 
    std::cout << boost::fusion::at_key<VAR(bar)::keys::bar2>(barI) << std::endl; 
} 
+0

正確に私が必要としたもの。ありがとう!私はBoost.Fusionがそれをやっているので、おそらく比較的簡単に行うことができることを知っていました。私は自分でプリプロセッサマクロに飛び込むことを計画していました。私は構造体フィールドのキーがないソリューションを選択しましたが、今では完全なソリューションを追加できます。すばらしいです! –

+0

理解できないことがある場合は、お気軽にお問い合わせください。私はもっ​​と時間があるときはいつでも、私がしたことを(実際に)より良く説明しようとします。 – llonesmiz

関連する問題