Hassan Syed
Hassan Syed

Reputation: 20496

C++ generic programming subtleties

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.

Upvotes: 2

Views: 298

Answers (3)

Serge Dundich
Serge Dundich

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

Chris Card
Chris Card

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

Potatoswatter
Potatoswatter

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

Related Questions