Почему это не сработает?
0. #define CONCAT(x, y) x ## y
1.
2. #define VAR_LINE(x) \
3. int CONCAT(_anonymous, __LINE__) = x
4.
5. #define VAR_LINE2(x) \
6. int _anonymous ## x = 1
7.
8. int main()
9. {
10. VAR_LINE(1);
11. VAR_LINE(1);
12. VAR_LINE(1);
13. VAR_LINE2(__LINE__);
14. }
Результат вышеупомянутого расширения макроса
int _anonymous__LINE__ = 1;
int _anonymous__LINE__ = 1;
int _anonymous__LINE__ = 1;
int _anonymous13 = 1;
Было бы удобно, если бы мне не пришлось писать этот макрос __LINE__ в качестве аргумента.
Думаю, проблема ясна. Я хочу иметь возможность генерировать анонимные переменные, чтобы этот макрос не выходил из строя с ошибкой переопределения при объявлении нескольких переменных в одной области. Моя идея состояла в том, чтобы использовать предопределенный макрос __LINE__, потому что никакая переменная никогда не будет объявлена в той же строке, как эта. Но меня беспокоит расширение макросов, не могли бы вы помочь?
Спасибо Люку Турэлю. Однако с предложенным решением возникла небольшая проблема. Между операндами и оператором ## должен быть пробел (очевидно, в стандарте сказано иное, но GCC со вкусом PS3 не расширил бы макрос должным образом, если бы между оператором и операндами не было пробелов).
#define _CONCAT(x,y) x ## y
#define CONCAT(x,y) _CONCAT(x,y)
Макрос VAR_LINE теперь дает:
int _anonymous10 = 1;
int _anonymous11 = 1;
int _anonymous12 = 1;
Было подтверждено, что это работает под Win32 (Visual Studio 2008), XBOX360 (Xenon) и PS3.
Но это означает, что вы полагаетесь на побочные эффекты. Если для метода требуется наличие определенного объекта, передайте этот объект в качестве параметра. Сделайте зависимость явной, это упростит обслуживание. Я предполагаю, что вы должны использовать интерфейс в стиле singleton для доступа к анонимным объектам?
В целом «анонимность - это плохо» - кто-то в будущем забудет создать объект и не осознает его важность до тех пор, пока программа не выйдет из строя, и даже тогда он не будет полностью уверен, почему. Называя объект и передавая его в качестве параметра, вы обнаружите ошибку во время компиляции.
У вас также есть проблемы с потоками - что, если два потока создают один и тот же анонимный объект - какой из них следует использовать?
Нет проблем с потоками, и анонимные объекты недоступны. Их единственная цель здесь - обеспечить время жизни объекта, и для этого требуется имя. Будь то анонимно или нет. Пример никоим образом не передает то, что я пытаюсь сделать, и поэтому я понимаю, что это может сбивать с толку.
Это не принципиально неправильно. В C++ 11 следовало добавить ключевое слово для анонимных переменных, чтобы не использовать макросы. Возможно, что-то вроде: int auto; Позволяет использовать ключевое слово auto вместо имени переменной. Да, это позволяет такие вещи, как «auto auto = 5.f;»





Вам нужно добавить уровень косвенности, чтобы __LINE__ был расширен:
#define _CONCAT_(x,y) x ## y
#define CONCAT(x,y) _CONCAT_(x,y)
#define VAR_LINE(x) int CONCAT(_anonymous, __LINE__) = x
Вот в чем дело, есть проблема с предложенным вами решением. Между операндами и оператором ## должен быть пробел. Предлагаемое вами решение должно быть следующим: #define _CONCAT_ (x, y) x ## y.
Что ж, это странно, в стандарте специально указано, что «Пробел вокруг токенов # и ## в определении макроса необязателен». (16.3.5 п.6). В любом случае, я соответствующим образом отредактирую свой ответ.
Действительно, я проверил это и с людьми на работе. Судя по всему, GCC со вкусом PS3 не расширил бы макрос должным образом, если бы между оператором и операндами не было пробелов.
Нет, я понимаю, почему вы так думаете. Анонимные переменные имеют множество применений. Мне нужно, чтобы продолжительность объектов была в области видимости. Без имени, анонимно оно или нет, они просто будут созданы и сразу после этого уничтожат тот же самый объект.