Need help with C Preprocessor Macro usage. Thanks!

Started by
11 comments, last by ynkm169 15 years, 8 months ago
Hi: I have been having lots of trouble with macros. I have these classes: class PrintD1X1F1 class PrintD2X2F2 class PrintD3X3F3 ... class PrintD100X100F100 #define PrintDXF(d,x,f) PrintD##d##X##x##F##f /////And I want to declare the class based on the arguments d, x, f void function (int d, int x, int f) { PrintDXF(d,x,f) printDXF; } However c++ doesn't allow me to do this. For example, this is valid PrintDXF(1,1,1) since it becomes PrintD1X1F1 after preprocessing. But PrintDXF(d,x,f) doesn't work since it becomes PrintDdXxFf.(Notice the parameters d,x,f aren't substituted) Thanks a lot in advance. Yujiao
Advertisement
The preprocessor operates before the code is parsed and sent to the compiler. It's the first step of the compilation process.

A function, such as:

void function (int d, int x, int f) {

PrintDXF(d,x,f) printDXF;

}

is called at run time, long after the preprocessor has performed it's task. That means there is no way that the preprocessor can know what values of d,x and f are passed to the function. The short of it is that you can't invoke a preprocessor macro as if it were a function. This limitation illustrates the difference between compile time and run time.

I'm not well versed in C++, but there's probably a way to do what you want using templates.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Connecting runtime data with compile-time generated classes is not easy. You will have to make the dynamic correspondence by manually writing the associated code which reads the runtime values of (d,x,f) and performs some work with the corresponding type. For instance:

template <class F> void select_type(int d, int x, int f, F call){# define SELECT_TYPE_POSS(_d,_x,_f) \     if (_d = d && _x = x && _f = f) call.run<PrintDXF(_d,_x,_f)>()  SELECT_TYPE_POSS(1,1,1);  SELECT_TYPE_POSS(2,2,2);  // ...  SELECT_TYPE_POSS(100,100,100);#undef SELECT_TYPE_POSS}struct myFunctor{  template<typename T> run()  {    T printDXF;    // Do things  }};void function(int d, int x, int f){  myFunctor func;  select_type(d,x,f,func);}
This is C++, C doesn't have classes.

Quote:I have these classes:

class PrintD1X1F1
class PrintD2X2F2
class PrintD3X3F3
...
class PrintD100X100F100


Why? What's the purpose of this?

Looking at the example, and your formulation, the following comes to mind:
template < int D, int X, int F >struct PrintDXF { };template < int D, int X, int F >void printDXF() {  PrintDXF<D,X,F> p;}int main() {  printDXF<1,1,1>();  printDXF<1,5,99>();  printDXF<100,100,100>();}


You cannot mix variables with compile-time constants though.

To do that, regardless of whether macros or templates are used, you need to use switch, which selects from all possible combinations. In this particular case, that's incredibly unwieldy.

But again, and most importantly - what is the purpose of this. It's very rare macros are needed, most commonly it's just the case of trying to something in suboptimal way.
Thanks for reply. They are helpful.

What I am trying to do is this:'

I have an abstract class and I want to provide many implementations of it.

For example class PrintD0X0F0 is one implementation and PrintD1X1F1 is another.

I want to user to select the implementation easily with this:

#define PrintDXF(d,x,f) PrintD##d##X##x##F##f

main {
int d = 1, x = 1, f = 1;
PrintDXF(d,x,f) printDXF;
IPrintItem* iPrintItem = &printDXF //here IPrintItem is the interface.
}

Doing it the bad way would probably like:

main {
int d, x, f;
cin >> d; cin >> x; cin >> f;

if(d == 0, x == 0, f == 0)
PrintD0X0F0 printDXF;
else if(d == 1, x == 0, f == 0)
PrintD1X0F0 printDXF;
else if(d == 1, x == 1, f == 0)
PrintD1X1F0 printDXF;
//...100 lines

IPrintItem* iPrintItem = &printDXF //here IPrintItem is the interface.
}
Quote:Original post by ynkm169
For example class PrintD0X0F0 is one implementation and PrintD1X1F1 is another.


If the only difference in implementation is a number, why do you create different classes?
If the implementation classes have differing behavior, why not give them a sane name?

Can you describe the differences between each implementation? If you give us something concrete, we will be better able to help.
Quote:Original post by rip-off
Can you describe the differences between each implementation? If you give us something concrete, we will be better able to help.


<code>

class IPrintItem {
virtual void setItem(Item* _item) = 0;
virtual void print( ostream & os ) = 0;
};

class IPrintD1X1F1 : IPrintItem {
virtual void setItem(Item* _item);
virtual void print( ostream & os );
};

//Here D, X, F are printing options. So I could having many styles for printing.
//X1 denotes one particular style and I want to mix lots of styles with X,D,F
//some implementations for example:

void PrintD0X0F0::print( ostream & os ){
os << std::endl;
}

void PrintD0X0F1::print( ostream & os ){
os << " \"" << "\" [$" << ", $" << ", " << "]";
}

void PrintD0X1F0::print( ostream & os ){
os << "<code></code>" << "<title></title>" << "<listPrice></listPrice>" << "<eStorePrice></eStorePrice>" << "<quantityInStock></quantityInStock>";
}

void PrintD0X1F1::print( ostream & os ){
os << " \"" << "\" [$" << ", $" << ", " << "]";
}

void PrintD1X0F0::print( ostream & os ){
os << item->getCode() << item->getTitle() << item->getListPrice() << item->getEStorePrice() << item->getQuantityInStock();
}

void PrintD1X0F1::print( ostream & os ){
os << item->getCode() << " \"" << item->getTitle() << "\" [$" << std::setiosflags( std::ios::fixed ) << std::setprecision( 2 )
<< item->getListPrice() << ", $" << item->getEStorePrice() << ", " << item->getQuantityInStock() << "]";
}

void PrintD1X1F0::print( ostream & os ){
os << "<code>" << item->getCode() << "</code>" << "<title>" << item->getTitle() << "</title>" << "<listPrice>"
<< item->getListPrice() << "</listPrice>" << "<eStorePrice>" << item->getEStorePrice() << "</eStorePrice>"
<< "<quantityInStock>" << item->getQuantityInStock() << "</quantityInStock>";
}

void PrintD1X1F1::print( ostream & os ){
os << "<code>" << item->getCode() << "</code>" << " \"" << "<title>" << item->getTitle() << "</title>" << "\" [$"
<< std::setiosflags( std::ios::fixed ) << std::setprecision( 2 ) << "<listPrice>" << item->getListPrice() <<
"</listPrice>" << ", $" << "<eStorePrice>" << item->getEStorePrice() << "</eStorePrice>" << ", "
<< "<quantityInStock>" << item->getQuantityInStock() << "</quantityInStock>" << "]";
}


</code>
Thanks for helping. Template is good but I guess it is not helpful here since I need different classes that do different things. It seems to have nothing to do with the template parameter.

In a nutshell, here is what I want and i guess it is encountered in real software development:

I have an abstract class and a great deal of implementations.
Based on some input options, I want to switch to a particular implementation.

Things to avoid:
A ton of if else statement to choose the particular implementation.


You could try to split the behaviors along D, X and F, so that you have a D-class, an X-class and an F-class (which you get from an array based on the value) and combine them in a printer class.

This topic is closed to new replies.

Advertisement