tags:

views:

305

answers:

7
+1  Q: 

C++ nested macros?

Is there any way, in C++, to define nested macros/constants within a class, in a similiar fashion to nested typedefs, or a method to acheive similiar functionality? The motive is generally for the macros to be used by templates.

class SomeClass
{
public:
    #define SomeConstant 123
};

int x=SomeClass::SomeConstant;

Ofcourse, static const members can do the job, but those are physical variables, while I'm looking for a simple macro-like behavior.

+2  A: 

Macro pre-processors generally don't have any idea of language context; thus they don't know what a "class" is making "nesting inside a class" not make sense in the first place.

For what you want, either use static const, or use the full name (assuming the preprocessor allows colons in macro names, not 100% sure on that) - though it won't allow you to inherit the constant on derived classes:

#define SomeClass::SomeConstant 123
Amber
Using the full name (if it is allowed) won't help when templates are thrown into the mix
Alex Deem
':' is _not allowed_ in the macro name.
Heath Hunnicutt
+2  A: 

Macros completely ignore scope - they are expanded before the C++ compilation. You just can't do that.

Use of static const often leads to no variable being allocated - the compiler treats it as a constant.

sharptooth
+6  A: 

You can't do what you want with macros. Macros have no concept of scoping.

But for simple int values you can do what you want with enums.

class SomeClass
{
public:
    enum {
        SomeConstant=123
        };
};

int x=SomeClass::SomeConstant;

A fully scoped name for the value, but no space taken for it, even in debug builds - you couldn't take its address if you wanted to.

Michael Burr
A: 

I don't understand your objection to using a static const. It will not effect the size of your class, and the compiler will optimise to achieve what you think you'd get from a macro.

Alex Deem
+1  A: 

You can do this with templates:

template < int someConstant = 123 > class SomeClass
{
public:
    void outputConstant() { cout << "We think the answer is:" << someConstant; }
}

But that isn't precisely what you want because you have to declare an instance of the class as:

int main(int argc, char *argv)
{
    SomeClass<123> myInstance;
}

I know others have explained the bit about macros, but allow me to add: #define is processed by the pre-processor, not the compiler. In the standard is a section called "translation phases" which explains this in more detail, but for your question the point is that macros are evaluated before the class is even compiled, and the scope at which the #define occurs is not known.

The authoritative book on this subject (programming with templates during the compile stage) is Modern C++ Design: Generic Programming and Design Patterns Applied, by Andrei Alexandrescu.

Heath Hunnicutt
A: 

"Static members are physical variables".

What's against this? The only reason to object to this would be memory usage. But since the member is static, the memory would only be occupied once with the intended content.

On the contrary, with a macro, the contend would be present at every single usage location in the binary.

EDIT: In case the variable is of an integral type, smaller than a pointer, it's probably best to define the constant in the class declaration. Optimizing compilers can then inline the value in the calling code, just like for a macro.

xtofl
Hmm. And with a static, the ADDRESS would be present at _every single usage location_ in the binary. So if it is a byte we are talking about...
Heath Hunnicutt
In case of a `char` (or another small, integral type), you can define it within the class declaration, and it will be inlined again.
xtofl
+4  A: 

Const values declared and defined in-place are exactly what you need here: the compiler can and will optimise them away completely so they end up being exactly the same as using the #define in the first place, but with the benefits of strict scoping.

class SomeClass {
  public:
   static const int someValue = 10;
};

This doesn't take up any extra space - no memory is allocated to store "someValue". You can prove this: if you try and use the "someValue" as a real object (ie you try and get its address), then the linker will tell you it's undefined.

Matt G
Strictly speaking there's one more detail if you use `static const` variables: you must have a `const int SomeClass::someValue;` definition somewhere (exactly once, but only if you otherwise use the member) or you're relying on undefined behavior. I know that this isn't a problem in reality, the linker can still throw away the storage if it's not really used, and the rule is pretty much ignored (and Stroustrup considers it a 'misfeature'), but them's the rules. C++03 9.4.2/4 (http://stackoverflow.com/questions/370283/why-cant-i-have-a-non-integral-static-const-member-in-a-class/370433#370433)
Michael Burr