Sign in to follow this  
ynkm169

Need help with C Preprocessor Macro usage. Thanks!

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
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
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
Quote:
Original post by ToohrVyk
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.


Thanks ToohrVyk.
I tried that and thought about a few design patterns.

For example, the Decorator Pattern.
I could potentially wrap the class I want with the D-class, an X-class and an F-class (here D,X,F are decorators).

However, it is pretty hard to do this:
D-class print something, X-class process D-class output and F class process X-class output.

Share this post


Link to post
Share on other sites
Quote:
Original post by ynkm169

However, it is pretty hard to do this:
D-class print something, X-class process D-class output and F class process X-class output.


How are individual implementations identified? Why 0-100? Are they auto-generated? Why such obscure semantics?

The problem of compositing classes here is a solved one, and not a matter of discussion. What remains, is figuring out how to do the lookup, which is the real problem.

The most important criteria in that will be where the qualifiers come from. Are they compile-time or run-time specified (read from file, for example).

If they compile-time, then the template solution is optimal.

If they are run-time, then there is no other way (in an algorithmic manner) than using a hash table. That table may, under certain circumstances, reduce to an array.

In all of solutions to run-time lookup, you have a factory method:
Interface * getInterface(int id);
The only question that remains is how to implement it. Since C++ doesn't support reflection, you will be stuck with switch statement or Interface * variations[100]; array, which you will need to populate manually.

At this point, you end up with this:
struct Processor {
PrintIF * printif;
ProcessIF * processif;
OutputIF * outputif;

void foo() {
printif->doit();
processif->doit();
outputif->doit();
}
};

Processor getInterface(int d, int x, int f)
{
Processor p;
p.printif = getPrintInterface(d);
p.processif = getProcessInterface(x);
p.outputif = getOutputInterface(f);
return p;
}


However, if you specify into more detail, then it's probably possible to find a more compact solution from implied context.

All of the above can obviously be rewritten with templates for full compile-time resolution.

Share this post


Link to post
Share on other sites
Thanks Antheus.

Your thought is exactly the solution I thought out.

Basically, Based on the value of X, D, F, I calculate the look up table entry using Horner's rule. Then I let the user select the particular implementation {class} he wants by calculating the index using the X, D, F.

#define addPrintClass(index,d,x,f) PrintD##d##X##x##F##f##* pClass; printClassLookup[##index].push_back(pClass)

void initPrintClassLookup(vector<PrintBase*>& printClassLookup) {
addPrintClass(0,0,0,0);
addPrintClass(1,0,0,1);
addPrintClass(2,0,1,0);
addPrintClass(3,0,1,1);
addPrintClass(4,1,0,0);
addPrintClass(5,1,0,1);
addPrintClass(6,1,1,0);
addPrintClass(7,1,1,1);
}

int getPrintClassIndex(int numDigits, vector<int>& featureIndicator, vector<PrintBase>&printClassLookup) {
int currVal = 0;
//calculate index based on Horner's Rule
for(int i = 0; i < featureIndicator.size(); i++)
currVal = numDigits * currVal + featureIndicator[i];
return currVal
}

in main:

switch( line[0] ) {
case 'd':
if( line[1] == '1' ) d = 1;
else d = 0;
case 'f':
if( line[1] == '1' ) d = 1;
else d = 0;
case 'x':
if( line[1] == '1' ) d = 1;
else d = 0;
}
featureIndicator.clear();
featureIndicator.push_back(d);
featureIndicator.push_back(x);
featureIndicator.push_back(f);

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this