Jump to content
  • Advertisement
Sign in to follow this  
ynkm169

Need help with C Preprocessor Macro usage. Thanks!

This topic is 3797 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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);
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.
}

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
Can you describe the differences between each implementation? If you give us something concrete, we will be better able to help.

Share this post


Link to post
Share on other sites
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>

Share this post


Link to post
Share on other sites
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.


Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!