Общие тонкости программирования на C++
Проблема, которую я имею, иллюстрируется в следующем коде.
#include <iostream>
#define X 4
int main()
{
std::cout << "should be 4: " << X << std::endl;
#define Y X + 4
std::cout << "should be 8: " << Y << std::endl;
#undef Y
#define Y X+0
#undef X
#define X Y+1
std::cout << "expecting 5: " << X << std::endl;
}
Ошибка:
test2.cc: In function ‘int main()’:
test2.cc:17: error: ‘X’ was not declared in this scope
Шаблон, который я пытаюсь эмулировать, - это расширение программы на уровне кода / сборки (очень похоже на то, как модули nginx подключаются во время компиляции). Мне нужно создать расширяемую структуру времени компиляции, которая является расширяемой (подключаемой) путем добавления #include
в моей сборке, это приводит к boost-mpl-vector с уникальным именем, содержащим все мои плагины. Так что если X
является уникальным конечным именем, X_0, X_1, X_2 являются именами, которые создаются по пути, поскольку вектор имеет mpl-вектор push_back
применяется к нему.
Я ЗНАЮ, что абстракции boost::preprocessor являются ключевыми, но я пока не хочу тратить время на их исследование, так как я создаю прототип той части системы, которая в конечном итоге будет модульной во время компиляции.
Итак, для дальнейшего использования,
- Почему я получаю ошибку выше?
- Как должен выглядеть правильный шаблон исходного препроцессора.
- Как выглядит правильный шаблон boost-preprocessor-library.
3 ответа
Компиляция с g++ -E дает это:
int main()
{
std::cout << "should be 4: " << 4 << std::endl;
std::cout << "should be 8: " << 4 + 4 << std::endl;
std::cout << "expecting 5: " << X+0 +1 << std::endl;
}
Таким образом, вы можете увидеть, почему вы получаете ошибку.
Почему бы не убить двух зайцев одним выстрелом и не использовать пространства имен.
// a.hpp:
namespace a {
const int module_id = 0;
class module_a : extension_module< module_id > { … };
}
#undef last_module
#define last_module a
// b.hpp:
namespace b {
const int last = last_module::module_id + 1;
class module_b : extension_module< module_id > { … };
}
#undef last_module
#define last_module b
Это гораздо менее "умно" и оставляет следы удостоверений личности.
Тем не менее, модули должны быть включены в том же порядке каждый раз, чтобы ODR работал.
Я не защищаю убийство любых птиц.
Проблема вашего примера кода в том, что у вас есть циклическая зависимость в макросах X и Y:
Y определяется как X+0, а X определяется как Y+1. Поэтому, когда макросы раскрываются (это происходит в том месте, где вы используете X), у вас возникает проблема.
ДОБАВЛЯТЬ:
Похоже, поведение таково: при расширении макроса X
внутри его определения имя X не определено в пространстве имен препроцессора, поэтому вы видите X+0+1 как расширение X.