如何在参数集的catersian产品中调用包含所有点的宏?

时间:2017-05-01 16:48:20

标签: c++ macros c-preprocessor metaprogramming

假设我有一个宏

FOO(a, b)

我希望使用a的某个(固定)可能值集来调用此宏;以及b的一组固定值。因此,如果我的b值为barbaz且我的b值为fizbang,我想要:

FOO(bar, fiz)
FOO(bar, bang)
FOO(baz, fiz)
FOO(baz, bang)

用新行或分号或两者分隔 - 这是一个小问题,所以让我们忽略它; 4次调用的确切顺序也不重要。

现在,如果我只有一个维度'参数,我可以使用威廉斯旺森的mechanism(如网站上所述;其中甚至还有github repository),然后写

MAP(SINGLE_PARAMETER_MACRO, bar, baz, quux)

获取

SINGLE_PARAMETER_MACRO(bar)
SINGLE_PARAMETER_MACRO(baz)
SINGLE_PARAMETER_MACRO(quux)

但问题是,我有两个维度;将__VA_ARGS__分成两个不同的集合,并从这些集合中迭代元素对的二维空间似乎是不可能/棘手的。

这可以(合理地)完成吗?

备注:

  • 我对基于C预处理器的解决方案很感兴趣,但是如果你因某些奇怪的原因而只能在C ++中运行,那也可以。
  • 解决方案必须只是编译时间,并且在C / C ++翻译单元中的所有地方都有效;特别是在类定义和文件范围内。
  • 你可能猜测这是XY problem,你是对的;但请不要选择我的动机,因为X和Y都很有趣恕我直言。
  • 如果您可以维护宏调用的字典顺序,那就太好了。

2 个答案:

答案 0 :(得分:3)

BOOST_REPEAT_PP可以帮到你。

例如,如果您有两个数字数组,则可以在c ++ 14中执行此操作:

#include <boost/preprocessor/repetition/repeat.hpp>
#include <array>
#include <iostream>

constexpr std::array<int, 2> a = {2, 4};
constexpr std::array<int, 3> b = {1, 3, 7};

#define MYNUMBER2(z, n, x) std::cout << a[x] << " " << b[n] << std::endl;
#define MYNUMBER(z, n, x) BOOST_PP_REPEAT(3, MYNUMBER2, n)

int main() {
  BOOST_PP_REPEAT(2, MYNUMBER, 0); // The "0" is actually not used
}

输出:

2 1
2 3
2 7
4 1
4 3
4 7

如果您不想使用std::array,您还可以采用以下方法(不需要c ++ 14):

#include <boost/preprocessor/repetition/repeat.hpp>
#include <iostream>

#define A_0 "bar"
#define A_1 "baz"
#define A_2 "ban"

#define B_0 "fiz"
#define B_1 "bang"

#define FOO(s1, s2) std::cout << s1 << " " << s2 << std::endl;
#define MYSTRING2(z, n, x) FOO(A_##x, B_##n)
#define MYSTRING(z, n, x) BOOST_PP_REPEAT(2, MYSTRING2, n)

int main() {
  BOOST_PP_REPEAT(3, MYSTRING, 0); // The "0" is actually not used
}

输出:

bar fiz
bar bang
baz fiz
baz bang
ban fiz
ban bang

答案 1 :(得分:1)

boost预处理器库可以在预处理器列表和序列上执行笛卡尔积。您没有指定要输入的预处理器数据类型...假设A和B是元组,并且您有可变参数,您可以这样做:

#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/to_tuple.hpp>
#include <boost/preprocessor/tuple/to_seq.hpp>

#define EVAL(...) __VA_ARGS__
#define FOO_SEMI_DELIM(R,SEQ_X) EVAL(FOO BOOST_PP_SEQ_TO_TUPLE(SEQ_X));
#define FOO_CARTESIAN(TUP_A,TUP_B) \
   BOOST_PP_SEQ_FOR_EACH_PRODUCT \
   ( FOO_SEMI_DELIM, \
     (BOOST_PP_TUPLE_TO_SEQ(TUP_A)) \
     (BOOST_PP_TUPLE_TO_SEQ(TUP_B)) \
   )

FOO_CARTESIAN((John,Jane),(Smith,Jones,Parker,Peterson))

由于FOO全部上限,我假设您想结束将FOO称为宏; EVAL允许您执行此操作。

您可以轻松将其扩展到更高尺寸的笛卡尔积。