【发布时间】: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;
}
不幸的是,这段代码的主要缺陷是我必须用数字5 对unroll 的每个调用进行硬编码。到时候我还不如写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 问题”的影响(少于问题,但仍然存在)。