0

我一直在努力尝试编写一个适当#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);

我感谢每一点帮助!

4

6 回答 6

7

使用您的宏的第一个版本,pMAKE(0,1,2,p);扩展为

p.0 = 0;
p.1 = 1;
p.2 = 2;;

换句话说,您已经使用,预处理了对x,成员的引用,y作为变量名(在赋值的左侧)和要被预处理器替换的标签(在右侧作业)。zptxyz

(正如 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)
于 2013-02-07T15:26:32.873 回答
6
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 };
于 2013-02-07T15:26:26.230 回答
3

这些错误是什么意思,为什么我会得到它们?

宏用参数替换所有出现的参数;所以

(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};
于 2013-02-07T15:29:49.983 回答
2

宏用作文本替换。宏的参数出现在替换列表中的任何地方,在文本上都被参数替换。因此,在您的情况下,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);
}
于 2013-02-07T15:31:49.713 回答
2

使用内联函数,

pt& pMake(int x, int y, int z, pt&p){
    p.x=x;
    p.y=y;
    p.z=z;
    return p;
};
于 2013-02-07T15:32:51.380 回答
1

.(x)成员访问意外地使用了参数的名称x。(此外,成员访问的第二个操作数不是表达式,因此括号不属于。)最佳做法是保持所有宏名称和宏参数全部大写,以防止命名冲突。并避免使用单个字符标识符。

#define POINT_MAKE(X,Y,Z,DEST)\
    (DEST).x = (X);\
    (DEST).y = (Y);\
    (DEST).z = (Z);
于 2013-02-07T15:29:27.487 回答