Общие тонкости программирования на 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 являются ключевыми, но я пока не хочу тратить время на их исследование, так как я создаю прототип той части системы, которая в конечном итоге будет модульной во время компиляции.

Итак, для дальнейшего использования,

  1. Почему я получаю ошибку выше?
  2. Как должен выглядеть правильный шаблон исходного препроцессора.
  3. Как выглядит правильный шаблон 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.

Другие вопросы по тегам