【问题标题】:Is there approach to do cartesian product on two lists with C Macro?有没有办法用 C 宏在两个列表上做笛卡尔积?
【发布时间】:2021-04-01 15:28:15
【问题描述】:

例如,我有这样的代码:

#define LIST_A \
    Element1 \
    Element2 \
    Element3

#define LIST_B \
    Element4 \
    Element5

// I'd like to perform some operations on tuples of LIST_A * LIST_B
// That is a set of tuples {(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)}

我面临的真正问题是我有一些 C++ 模板函数,例如:

// Left, Right, Result can be any numeric types
template <typename Left, typename Right, typename Result>
struct Function
{
    void apply(const Left & lhs, const Right & rhs, Result & res);
};

我想用尽Function 的专业化空间。

例如我有以下输入数据类型:

#define LEFT_TYPE_LIST\
    int32_t \
    int64_t 

#define RIGHT_TYPE_LIST\
    uint32_t \
    uint64_t

我想将LEFT_TYPE_LISTRIGHT_TYPE_LIST 申请到Function&lt;Left, Right, Result&gt;

有没有实用的方法来实现这个?

【问题讨论】:

  • 由于您使用的是 C++,您是否有特定的原因要使用宏来执行此操作?

标签: c++ macros c-preprocessor


【解决方案1】:

如果你不介意笨拙的语法,你可以使用X macros:

#define TYPES1(WITH, _)  \
    _(WITH, Apple)       \
    _(WITH, Orange)      \
    _(WITH, Pear)

#define TYPES2(WITH, _)  \
    _(WITH, Apple)       \
    _(WITH, Kumquat)

现在您可以像这样定义宏:

#define CMP(A, B) compare(A, B);
#define COMPARE(W, T) W(T, CMP)

并将列表应用于彼此(但不幸的是不是对自己):

TYPES1(TYPES2, COMPARE)
TYPES2(TYPES1, COMPARE)

这是如何工作的?传递给宏列表的_ 参数本身就是一个宏,它会根据它的参数进行扩展。这里,_ 宏必须是带有两个参数的宏。

这通常是为了用不同的宏建立不同的上下文,例如让参数扩展为 enum 常量,然后再扩展为字符串化的名称。在这里,不同的上下文是调用的级别。 WITH 参数要么是第一个对象(在最低级别),要么是另一个 X 宏。

为了完整起见:宏只能让您到目前为止。有时,最好通过创建可以包含的文件的脚本或程序在外部准备此类数据。您可以将“代码生成”作为构建过程的一部分。如果你有很多这样的宏,或者如果宏变得奇怪,那可能是一个更好的选择。

【讨论】:

  • 太棒了。我以前知道 X Macro,但不知道它可以为另一个宏做一个占位符。我会尝试一下。顺便说一句,我确实生成了集成测试,这只是对单元测试的增强。
【解决方案2】:

如果没有宏,您可能会执行以下操作:

template <typename T> struct tag { using type = T; };

using LEFT_TYPE_LIST = std::tuple<tag<int32_t>, tag<int64_t>>;
using RIGHT_TYPE_LIST = std::tuple<tag<uint32_t, tag<int64_t>>; 

然后

std::apply([](auto... lefts){
    auto f = [](auto left){
        std::apply([left](auto... rights){
            (Function<typename decltype(left)::type,
                      typename decltype(rights)::type>(),
             ...);
        }, RIGHT_TYPE_LIST{});
    };
    (f(lefts), ...);
}, LEFT_TYPE_LIST{});

Demo

【讨论】:

    猜你喜欢
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多