[英]C++ writing a proper function-like macro
我一直在努力尝试编写一个像#define
函数一样的宏,但被卡住了。 这是我正在使用的示例:
#include <iostream>
#define pMAKE(x,y,z,dest)\
(dest).(x) = (x);\
(dest).(y) = (y);\
(dest).(z) = (z);
struct pt {
double x, y, z;
};
int main() {
pt p;
pMAKE(0,1,2,p);
return 0;
}
我得到的错误:
A.cpp: In function ‘int main()’:
A.cpp:13: error: expected unqualified-id before ‘(’ token
A.cpp:13: error: expected unqualified-id before ‘(’ token
A.cpp:13: error: expected unqualified-id before ‘(’ token
错误是什么意思,为什么我会得到它们? 我设法使以下人员按自己想要的方式工作,但是老实说我很幸运,我真的不明白发生了什么。
#define pMAKE(X,Y,Z,dest)\
dest.x = (X);\
dest.y = (Y);\
dest.z = (Z);
我非常感谢您的帮助!
对于您的宏的第一个版本, pMAKE(0,1,2,p);
扩展到
p.0 = 0;
p.1 = 1;
p.2 = 2;;
换句话说,您已经通过使用x
, y
, z
作为变量名(在分配的左侧)和标签来替换了对pt
的x
, y
, z
成员的引用,这些标签将被pre-处理器(在分配的右侧)。
(正如Konrad Rudolph指出的那样),不幸的是,您的宏还有另一个严重的错误。 考虑以下形式的代码
pt p;
if (foo)
pMAKE(0,1,2,p);
扩展到
pt p;
if (foo)
p.x = 0;
p.y = 1; // happens regardless of 'foo' test
p.z = 2;; // happens regardless of 'foo' test
您可以通过将宏更改为来解决此问题(并消除烦人的多余分号)
#define pMAKE(X,Y,Z,dest)\
do { \
(dest).x = (X);\
(dest).y = (Y);\
(dest).z = (Z);\
} while (0)
struct pt {
double x, y, z;
pt(double _x, double _y, double _z) : x(_x), y(_y), z(_z) { }
};
pt p (0.0, 1.0, 2.0);
不要在C ++中使用宏。
或者,就像@potatoswatter建议的那样,立即
在C ++ 11中
完成它
struct pt { double x, y, z; };
pt p = { 0.0, 1.0, 2.0 };
错误是什么意思,为什么我会得到它们?
宏将所有出现的参数替换为参数; 所以
(dest).(x) = (x)
变成
(dest).(0) = (0)
废话 编译器需要一个成员名称(一个标识符,该标识符在语言语法中称为“ unqualified-id”),但改为看到(0)
。
在第二个版本中, x
不是参数名称,因此dest.x
不会更改。
更好的方法是避免使用宏。 使用功能:
pt make_pt(double x, double y, double z) {
pt p;
p.x = x;
p.y = y;
p.z = z;
return p;
}
int main() {
pt p = make_pt(0,1,2);
}
或者只使用聚合初始化:
int main() {
pt p = {0,1,2};
}
并且在C ++ 11中,从初始化程序列表进行赋值:
p = {4,5,6};
宏用作文本替换。 宏的参数出现在替换列表中的任何地方,都将在文本上替换为参数。 因此,在您的情况下, pMAKE(0, 1, 2, p);
扩展为:
(p).(0) = (0);
(p).(1) = (1);
(p).(2) = (2);;
(实际上,由于宏不保留换行符,因此将全部放在一行上,但是为了清楚起见,我将其放在三行上)。
在您的情况下,您不需要宏。 您需要一个内联函数(可能是pt
的成员函数或构造函数)。 仅在需要文本性质的地方使用宏(例如,将标记合并为标识符等)。 对于其他所有功能,请使用(内联)函数。 像这样:
struct pt
{
double x, y, z;
pt(double ax, double ay, double az) : x(ax), y(ay), z(az) {}
};
int main()
{
pt p(0, 1, 2);
}
使用内联函数
pt& pMake(int x, int y, int z, pt&p){
p.x=x;
p.y=y;
p.z=z;
return p;
};
.(x)
成员访问不小心使用了参数x
的名称。 (此外,成员访问的第二个操作数也不是表达式,因此不属于括号。)最佳做法是将所有宏名称和宏参数都保留在所有大写形式中,以防止命名冲突。 并避免使用单个字符标识符。
#define POINT_MAKE(X,Y,Z,DEST)\
(DEST).x = (X);\
(DEST).y = (Y);\
(DEST).z = (Z);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.