【问题标题】:C++ Expand certain macros before othersC++ 在其他宏之前扩展某些宏
【发布时间】:2021-10-06 02:58:05
【问题描述】:
#include <iostream>
using namespace std;

#define MAX 5

#define unroll1(expr) expr();
#define unroll2(expr) expr(); unroll1(expr);
#define unroll3(expr) expr(); unroll2(expr);
#define unroll4(expr) expr(); unroll3(expr);
#define unroll5(expr) expr(); unroll4(expr);
#define unroll6(expr) expr(); unroll5(expr);
#define unroll7(expr) expr(); unroll6(expr);
#define unroll8(expr) expr(); unroll7(expr);
#define unroll(num, expr) unroll##num(expr);

void print() {cout << "Hello World!" << endl;}

int main()
{
    unroll(MAX, print);
    unroll(MAX, print);
    unroll(MAX, print);
    return 0;
}

此代码导致错误,因为 unroll(MAX, print) 扩展为 unrollMAX(print),这是一个未定义的表达式。

我想要的是让预处理器在unroll(MAX, print)的参数列表中看到MAX标记,然后解析为unroll(5, print),这样它就可以扩展为unroll5(expr)

以下代码编译。

#include <iostream>
using namespace std;

#define MAX 5

#define unroll1(expr) expr();
#define unroll2(expr) expr(); unroll1(expr);
#define unroll3(expr) expr(); unroll2(expr);
#define unroll4(expr) expr(); unroll3(expr);
#define unroll5(expr) expr(); unroll4(expr);
#define unroll6(expr) expr(); unroll5(expr);
#define unroll7(expr) expr(); unroll6(expr);
#define unroll8(expr) expr(); unroll7(expr);
#define unroll(num, expr) unroll##num(expr);

void print() {cout << "Hello World!" << endl;}

int main()
{
    unroll(5, print);
    unroll(5, print);
    unroll(5, print);
    return 0;
}

不幸的是,这段代码的主要缺陷是我必须用数字5unroll 的每个调用进行硬编码。到时候我还不如写unroll5

我需要的是定义一个保存5 值的常量的能力,这样我就可以在整个程序中使用该常量的名称,而不是5 的硬编码值。这样,如果我决定更改常量的值,我就不必更改使用它的程序部分。这是一个非常基本的编程原则,所以看起来应该有一个非常简单的方法来做到这一点。有什么建议吗?

【问题讨论】:

  • #define MAX 5 更改为 constexpr auto MAX = 5; 如果你有 C++11,特别是如果你有带有内联变量的 C++17,没有理由使用 #define 来定义常量.如果你不能使用 C++11 或新的,你仍然可以使用const int MAX = 5;,它将是一个编译时间常数。
  • 使用#define concat(a, b) a##b#define unroll(num, expr) concat(unroll, num)(expr);
  • 为什么在这里使用宏?这里的模板将以干净整洁的方式完成这项工作,对我来说这听起来像XY problem。你能解释一下这个宏应该解决什么样的问题吗?
  • @Marek R 假设我想展开函数以外的东西,例如 switch 语句案例。我不能在函数或 lambda 中嵌入 switch 语句 case,然后使用 C++ 模板展开它。我需要使用 C 宏。
  • @LoganSchlick:然后使用edit 更详细地描述这一点。有很好的解决方案可以像 switch 语句一样工作。如果你能描述为什么你需要这个宏,那么我们可以提出更好的方法。也许您正在尝试在枚举和字符串之间进行转换?也许您正在为某些课程构建反射,也许......此示例旨在向您展示您的评论仍然受到“XY 问题”的影响(少于问题,但仍然存在)。

标签: c++ macros


【解决方案1】:

C 宏不擅长与 C++ 实体交互(例如,constexpr 值可能是解决方案)。如果您坚持使用模板(尽可能),则不存在此问题。在您的情况下,您可以让编译器为您完成所有展开:

template<typename F, std::size_t... n>
constexpr void unroll(F f, std::index_sequence<n...>) {
    (..., (void)(n, f())); // repeat n times ignoring the in-between results
}

int main() {
    auto expr = [] { std::cout << "Hello world!\n"; };
    auto constexpr max = 5;
    unroll(expr, std::make_index_sequence<max>{}); // becomes expr(), expr(), expr(), expr(), expr();
}

【讨论】:

  • 是的,但我需要使用 C 宏,因为有时我想展开函数以外的东西。例如,如果我想展开 switch 语句案例怎么办?此外,如果我使用模板,编译器并不总是内联 lambda 表达式。
  • @LoganSchlick 展开开关盒:stackoverflow.com/a/46282159/12816539。不内联应该内联的内容是不太可能的,但如果你设法找到一个案例,你有一个备份:stackoverflow.com/questions/7108797/…
猜你喜欢
  • 1970-01-01
  • 2017-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2011-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多