@semenyakinVS
Писатель кода и не только

Как создать через макросы уникальный префикс к генерируемому имени типа на этапе компиляции?

Пытаюсь сделать систему для выполнения действий до запуска функции main(). Нужно для регистрации метаинформации о классах. Решил делать через глобальные переменные в cpp-файлах:

// Работает за счёт выполнения кода конструктора при инициализации глобальной переменной. До main
class BeforeMainHelper { public: BeforeMainHelper() { /* Before main start actions */ } } __helper__;


Проблема возникает в случаи, если нужна подобная регистрация больше чем один раз в рамках одного cpp-файла. Проблема по очевидным причинам. Конфликт имён.

Нужен механизм генерации уникальных имён для макросов. В начале я хотел использовать конкатенированные значения встроенных макросов __line__ и __file__ (комбинация, уникально задающая строку в рамках всего проекта). Но __file__ представляет из себя строковую переменную, которую нельзя конкатенировать в качестве части имени переменной. Чтобы заменить бэкслеши в пути файла на нижние подчёркивания у меня недостаточно чёрной компайл-тайм магии - не знаю как такое сделать.

Я прочитал про другую макросную "переменную" - __counter__. Не смотря на то, что она не входит в стандарт, решил попробовать с ней что-нибудь придумать. Столкнулся с другой проблемой - мне же нужен дважды один и тот же идентификатор (в начале для типа, потом для конструктора). Если использовать __counter__, он инкрементиться после первого использования, и имена у класса и конструктора становятся разными.

Таким образом я попал в тупик, из которого не знаю как выйти. Сейчас, во время тестирования, всё работает на конкатенации с номером строки. Но так оставлять это дело нельзя - могут быть очень неприятные, плохо отлавливаемые баги.

Помогите, пожалуйста, если кто имел дела с подобными штуками!
  • Вопрос задан
  • 677 просмотров
Решения вопроса 1
@Mace_UA
__FILE__ юзать не нужно, достаточно помещать классы в анонимные пространства имён. Такие классы будут уникальными для каждой единицы компиляции. Тогда будет достаточно просто прикрутить __LINE__ к идентификатору объекта класса. А сам класс, увы, придётся определять отдельным макросом, раз нужна возможность создавать по несколько объектов.

Вот небольшой пример. Проект из трёх файлов.
Приём с конкатенацией числа и идентификатора с помощью макросов взят отсюда:
stackoverflow.com/questions/1597007/creating-c-mac...

"header.hpp":
#ifndef HEADER_HPP_INCLUDED
#define HEADER_HPP_INCLUDED

#include <iostream>

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)

#define CLASS_MAGIC                                                           \
    namespace                                                                 \
    {                                                                         \
        struct FixedNameClass                                                 \
        {                                                                     \
            explicit FixedNameClass(int line)                                 \
            {                                                                 \
                std::cout << "Hello from \"" << __FILE__ <<                   \
                             "\", line " << line << std::endl;                \
            }                                                                 \
        };                                                                    \
    }

#define OBJECT_MAGIC                                                          \
    namespace                                                                 \
    {                                                                         \
        FixedNameClass TOKENPASTE2(variable_name_object, __LINE__)(__LINE__); \
    }

#endif // HEADER_HPP_INCLUDED


"main.cpp":
#include "header.hpp"

CLASS_MAGIC
OBJECT_MAGIC
OBJECT_MAGIC
OBJECT_MAGIC

int main()
{
}

OBJECT_MAGIC
OBJECT_MAGIC


"other.cpp":
#include "header.hpp"

CLASS_MAGIC
OBJECT_MAGIC
OBJECT_MAGIC


Вывод:
Hello from "other.cpp", line 4
Hello from "other.cpp", line 5
Hello from "main.cpp", line 4
Hello from "main.cpp", line 5
Hello from "main.cpp", line 6
Hello from "main.cpp", line 12
Hello from "main.cpp", line 13
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы