使用 Boost.Preprocessor 生成一组 class 模板的标记和索引特化

Generate a set of tagged and indexed specializations of a class template using Boost.Preprocessor

需要创建一个宏来生成一组由标签和索引专门化的结构重载。我尝试了以下方法:

#include <boost/preprocessor/seq/for_each_i.hpp>

template< typename /*tag*/, int /*index*/ >
struct S;

#define GEN(ignored, tilda, index, type_name) \
    template<> struct S< struct BOOST_PP_SEQ_TAIL(type_name), index > \
    { BOOST_PP_SEQ_HEAD(type_name) BOOST_PP_SEQ_TAIL(type_name); };

#if 1
BOOST_PP_SEQ_FOR_EACH_I(GEN, ~, ((int)(i)))
#else
// above should be equiv to:
template<> struct S< struct i, 0 > { int i; };
#endif

int main()
{
    S< i, 0 >{}.i; // check if accessible
}

但是报错:

prog.cc:8:111: error: wrong number of template arguments (1, should be 2)
 #define GEN(ignored, tilda, index, type_name) template<> struct S< struct BOOST_PP_SEQ_TAIL(type_name), index > { BOOST_PP_SEQ_HEAD(type_name) BOOST_PP_SEQ_TAIL(type_name); };
                                                                                                               ^
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:85:66: note: in expansion of macro 'GEN'
 # define BOOST_PP_SEQ_FOR_EACH_I_M_I(r, macro, data, seq, i, sz) macro(r, data, i, BOOST_PP_SEQ_HEAD(seq))
                                                                  ^~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:80:49: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_M_I'
 #    define BOOST_PP_SEQ_FOR_EACH_I_M_IM(r, im) BOOST_PP_SEQ_FOR_EACH_I_M_I(r, im)
                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:79:45: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_M_IM'
 #    define BOOST_PP_SEQ_FOR_EACH_I_M(r, x) BOOST_PP_SEQ_FOR_EACH_I_M_IM(r, BOOST_PP_TUPLE_REM_5 x)
                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:79:77: note: in expansion of macro 'BOOST_PP_TUPLE_REM_5'
 #    define BOOST_PP_SEQ_FOR_EACH_I_M(r, x) BOOST_PP_SEQ_FOR_EACH_I_M_IM(r, BOOST_PP_TUPLE_REM_5 x)
                                                                             ^~~~~~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/control/iif.hpp:32:31: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_M'
 # define BOOST_PP_IIF_1(t, f) t
                               ^
/usr/local/boost-1.62.0/include/boost/preprocessor/repetition/detail/for.hpp:22:37: note: in expansion of macro 'BOOST_PP_FOR_1_C'
 # define BOOST_PP_FOR_1(s, p, o, m) BOOST_PP_FOR_1_C(BOOST_PP_BOOL(p(2, s)), s, p, o, m)
                                     ^~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/cat.hpp:29:34: note: in expansion of macro 'BOOST_PP_FOR_1'
 #    define BOOST_PP_CAT_I(a, b) a ## b
                                  ^
/usr/local/boost-1.62.0/include/boost/preprocessor/control/iif.hpp:32:31: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EXEC'
 # define BOOST_PP_IIF_1(t, f) t
                               ^
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:30:55: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK'
 #    define BOOST_PP_SEQ_FOR_EACH_I(macro, data, seq) BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK(macro, data, seq)
                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:10:1: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I'
 BOOST_PP_SEQ_FOR_EACH_I(GEN, ~, ((int)(i)))
 ^~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:8: note: provided for 'template<class, long unsigned int <anonymous> > struct S'
 struct S;
        ^
prog.cc: In function 'int main()':
prog.cc:16:8: error: 'i' was not declared in this scope
     S< i, 0 >{}.i; // check if accessible
        ^
prog.cc:16:13: error: template argument 1 is invalid
     S< i, 0 >{}.i; // check if accessible
             ^

宏的struct BOOST_PP_SEQ_TAIL(type_name)部分好像不能正确处理,为什么呢?如果我将第一次出现的 BOOST_PP_SEQ_TAIL(type_name) 替换为 i,则代码可以正常编译。

错误的来源是什么?

为了简洁起见,我删除了 #include <cstdint>,但尝试使用 -P -E 进行编译,它将只输出预处理器的结果 运行,这在调试时非常有价值 Boost.PP 程序。

其输出为:

template< typename , int >
struct S;
template<> struct S< struct (i), 0 > { int (i); };
int main()
{
    S< i, 0 >{}.i;
}

错误很明显:struct (i)int (i) 是无效语法。

This answer 可能会帮助您解决这个问题。

这是我的解决方案,即创建我自己的小 tuple-accessing 宏:

#include <boost/preprocessor/seq/for_each_i.hpp>

template< typename /*tag*/, int /*index*/ >
struct S;

#define FIRST(a, b) a
#define SECOND(a, b) b

#define GEN(ignored, tilda, index, type_name)                           \
    template<> struct S< struct SECOND type_name, index > \
    { FIRST type_name SECOND type_name; };

#if 1
BOOST_PP_SEQ_FOR_EACH_I(GEN, ~, ((int, i)))
#else
// above should be equiv to:
template<> struct S< struct i, 0 > { int i; };
#endif

int main()
{
    S< i, 0 >{}.i; // check if accessible
}