BOOST_PP_SEQ_ELEM嵌套宏中的BOOST_PP_SEQ_ADD?

BOOST_PP_SEQ_ELEM with BOOST_PP_SEQ_ADD in nested macro?

本文关键字:BOOST SEQ PP ADD 嵌套 ELEM      更新时间:2023-10-16

我相信你可以使用BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(n,1),sequence),但我似乎不能完全确定为什么下面的EXTRACT宏无法编译"提供的参数太少,无法像宏一样工作"。

#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/logical/not.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <iostream>
// attempt 2.7 beta
#define EXTRACT(z, n, args) 
BOOST_PP_IIF(
/* on every third index */ 
BOOST_PP_NOT(BOOST_PP_MOD(n,3)),
/* check the flag */ 
BOOST_PP_IIF(BOOST_PP_SEQ_ELEM(n,args),
/*BOOST_PP_SEQ_ELEM(n,args),*/ 
BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(n,1),args),
"narp"
),
)
// absurd wrapper for extract
#define ALL_ARGS(args) BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(args),EXTRACT,args)
// every third element is a "flag"
//                   v          v
#define MY_SEQUENCE (1)(int)(z)(0)(float)(y)
int main(int argc, const char **argv) {
std::cout <<
BOOST_PP_STRINGIZE(ALL_ARGS(MY_SEQUENCE))
<< std::endl;
}

这个例子远非我想用这个做的,但现在我只是想弄清楚如何获得实际的intzfloaty

如果重要,实际目标是实例化模板。 我有一系列模板类,但无法弄清楚如何实例化

//                          vvvvvvvvvvvv
template <class X> void foo(SomeThing<X> varName);

所以这里的标志让我知道SomeThing是否需要<X>。 也许有更简单的方法可以解决这个问题? 我已经在模板中类的BOOST_PP_SEQ_FOR_EACH内,所以我唯一能弄清楚该怎么做的就是传递这个丑陋的参数序列。 FWIW 我知道int<X>无效,这只是测试......

诊断提示

通常,预处理器宏比"小程序"更容易使用预处理器进行调试。 例如,您在此处拥有的内容需要完整的编译和启动才能看到问题;但是如果你注释掉#include <iostream>#include <boost/preprocessor/stringize.hpp>,并将整个主函数替换为ALL_ARGS(MY_SEQUENCE),那么你可以简单地启动你的预处理器并直接查看它的输出;无需编译/运行。

这不仅更快,而且你可以在代币级别上玩,生产可以帮助你的东西,而不必担心生产可以编译的东西。

跟踪问题

使用上面的转换,我通过将参数EXTRACT更改为EXTRACT_来执行ALL_ARGS的单个扩展(在重现问题之后)。 这迭代得很好。 接下来,我将ALL_ARGS更改为扩展的输出,将每个EXTRACT_分解为单独的行并添加人工标签,然后将EXTRACT_改回EXTRACT;例如:

0_  EXTRACT(2, 0, (1)(int)(z)(0)(float)(y))
1_  EXTRACT(2, 1, (1)(int)(z)(0)(float)(y))
...

再次通过预处理器运行它表明所有扩展都很好,除了第六个:

5_  EXTRACT(2, 5, (1)(int)(z)(0)(float)(y))

考虑到这一点,很容易发现。 问题确实出在这一部分:

BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(n,1),args)

。当EXTRACT在 n=5 的情况下运行时,这相当于BOOST_PP_SEQ_ELEM(6, (1)(int)(z)(0)(float)(y))。 这里没有元素偏移量 6,因此宏崩溃了。 请注意,BOOST_PP_NOT(BOOST_PP_MOD(5,3))0,因此外部BOOST_PP_IIF不会选择内部,但它仍然必须对其进行评估

替代方法

也许有更简单的方法可以解决这个问题?

绝对。 使用不同的数据结构。 在这里,您的策略是使用大小为 3*n 的序列来表示某个 n,然后在序列中每 3 个项目中挑选出。

通过一些摆弄,您当然可以做到这一点,但是您需要这样做的全部原因是因为您实际上没有一系列物品......相反,您有一系列3 个项目的集合。 如果您将数据结构更改为 3 元组序列,这将变得容易得多;您只需要一个IIF、一个FOR_EACH和几个工作宏:

#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define MY_SEQUENCE ((1,int,z))((0,float,y))
#define APPLY_EXTRACT(r,data,elem) EXTRACT elem
#define EXTRACT(FLAG_,TYPE_,PNAME_) BOOST_PP_IIF(FLAG_, TYPE_, "narp")
#define ALL_ARGS(args) BOOST_PP_SEQ_FOR_EACH(APPLY_EXTRACT, _, MY_SEQUENCE)
ALL_ARGS(MY_SEQUENCE)

在堆叠歪歪上看到这个