使用 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
}
需要创建一个宏来生成一组由标签和索引专门化的结构重载。我尝试了以下方法:
#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
}