Reputation: 20496
The problem I have is illustrated in the following code.
#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;
}
The error:
test2.cc: In function ‘int main()’:
test2.cc:17: error: ‘X’ was not declared in this scope
The pattern I am trying to emulate is extending a program at code/build level(much like how nginx modules are wired up at compile-time). I need to build up an extensible compile time structure, which is extensible(plugable) by adding #include
s to my build, that results in a boost-mpl-vector with a unique name that contains all of my plugins. So if X
is the unique end name, X_0, X_1, X_2 are the names that are built up along the way as the vector has mpl-vector push_back
applied to it.
I KNOW the abstractions of boost::preprocessor are key, but I don't want to commit the time to researching it just yet, as I'm prototyping part of the system that will eventually be compile-time modularized.
So, for future reference,
Upvotes: 2
Views: 298
Reputation: 4439
The problem of your code sample is that you have circular dependency in X and Y macros:
Y is defined as X+0 and X is defined as Y+1. So when macros are expanded (that happens at the point where you use X) you have a problem.
ADD:
It seems that behaviour is this: when expanding macro X
inside its definition name X is not defined in preprocessor name space so you see X+0+1 as X expansion.
Upvotes: 2
Reputation: 3266
compiling with g++ -E gives this:
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;
}
So you can see why you get the error.
Upvotes: 5
Reputation: 137920
Why not kill two birds with one stone and use namespaces.
// 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
This is way less "clever," and leaves a trail of ID's.
However, the modules do need to be included in the same order every time for the ODR to work.
I do not advocate killing any birds.
Upvotes: 4