директива — C ++ пишет правильный функциональный макрос

Я бился головой, пытаясь написать правильное #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);

Я ценю каждую помощь!

0

Решение

С первой версией вашего макроса, pMAKE(0,1,2,p); расширяется до

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

Другими словами, вы предварительно обработали ссылки на x, y, z Члены pt используя x, y, z как имена переменных (слева от назначений), так и метки, подлежащие замене препроцессором (справа от назначений).

(Как отмечает Конрад Рудольф) К сожалению, в вашем макросе все еще есть серьезная ошибка. Рассмотрим код формы

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)
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 };
6

Что означают ошибки и почему я их получаю?

Макрос заменяет все вхождения его параметров с аргументами; так

(dest).(x) = (x)

становится

(dest).(0) = (0)

это ерунда. Компилятор ожидает имя члена (идентификатор, называемый «неквалифицированным идентификатором» в синтаксисе языка), но видит (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};
3

Макросы работают как текстовый замена. Везде, где параметр макроса появляется в списке замены, он текстуально заменяется аргументом. Так что в вашем случае, 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);
}
2

Используйте встроенную функцию,

pt& pMake(int x, int y, int z, pt&p){
p.x=x;
p.y=y;
p.z=z;
return p;
};
2

.(x) элемент доступа случайно использует имя параметра x, (Кроме того, второй операнд доступа к члену не является выражением, поэтому круглые скобки не принадлежат.) Рекомендуется сохранять все имена макросов и параметры макросов во всех заглавных буквах, чтобы избежать конфликтов имен. И избегайте односимвольных идентификаторов тоже.

#define POINT_MAKE(X,Y,Z,DEST)\
(DEST).x = (X);\
(DEST).y = (Y);\
(DEST).z = (Z);
1
По вопросам рекламы [email protected]