2

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 #includes 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,

  1. Why am I getting an error above ?
  2. What should the correct raw preprocessor pattern look like.
  3. What does the correct boost-preprocessor-library pattern look like.
Hassan Syed
  • 20,075
  • 11
  • 87
  • 171
  • 1
    have you tried just running this through the preprocessor to see what the c++ compiler is trying to compile? – Chris Card Apr 08 '11 at 09:16

3 Answers3

5

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.

Chris Card
  • 3,216
  • 20
  • 15
4

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.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • I have been staring at your answer for the last 20 minutes, the eureka just hit. template specialization via const integers + namespaces is indeed a clean and elegant solution to my problem, and I don't have to pull in boost MPL or preprocessor. Their are too many parallel levels of indirection in C++ :D. I will accept the `GCC -E` answer since it's most relevant to the question, however your answer is of higher overall value and is the solution I will adopt. – Hassan Syed Apr 08 '11 at 09:39
  • @Hassan: Lol, I didn't discuss the `gcc -E` results because I assumed you'd already done that, and only wanted a solution :vP – Potatoswatter Apr 08 '11 at 09:41
2

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.

Serge Dundich
  • 4,221
  • 2
  • 21
  • 16