#defines a case for a valid use for them -- maybe

  • Thread starter Thread starter Andrew Ch. _
  • Start date Start date
A

Andrew Ch. _

Guest
I think that it is generally understood that in most cases the use of #defines in C++ is to be discouraged, and for very good reasons. However, I have used a pattern that makes use of #defines for many years that I have not found a good alternative to. I am putting this onto the forum for discussion and do not mind being shot down in flames (on condition that a better alternative is given).

The scenario is this. I am modelling electrical components and the pins on them. Within the model of a component I need to be able to access pins by enumeration (so that I can perform the component modelling logic). Pins on a component also need to have names that match the real life pin names on the component. I would like to make sure that the enumerations for pins always match up with the pin names and never get out of step. (If a new pin gets added I want to ensure that when adding it I do not accidentally misalign the enumeration and name.) The pattern I use for this is shown in the very much simplified example below. Imagine I am modelling a component that has real life pin names J1_A, J1_B, J1_C, J2_A, J2_B, J2_C and J2_D:

// System includes...
#include <iostream>
#include <memory>
#include <vector>
#include <string>



using namespace std;





// The following #define is used to ensure that the pin names, and the
// enumerations for the pins are kept in sync. To use it: -
// - Define PIN_ITEM suitably (e.g. to extract the pin name etc.)
// - Insert the text PINS_LIST as required.
#define PINS_LIST \
/* Name Enumeration */ \
PIN_ITEM ( "J1_A", J1_A ) \
PIN_ITEM ( "J1_B", J1_B ) \
PIN_ITEM ( "J1_C", J1_C ) \
PIN_ITEM ( "J2_A", J2_A ) \
PIN_ITEM ( "J2_B", J2_B ) \
PIN_ITEM ( "J2_C", J2_C ) \
PIN_ITEM ( "J2_D", J2_D ) \
// End of PINS_LIST




// Pin names.
// Create an array of the names of all the pins. To do this we define
// PIN_ITEM to extract the "Name" portion given in the PINS_LIST.
#undef PIN_ITEM
#define PIN_ITEM( Name, Enumeration ) Name,
string PinNames[] = { PINS_LIST } ;

// Pin enumerations.
// Create an enueration for the pins. To do this we define PIN_ITEM to extract
// the "Enumeration" portion given in the PINS_LIST. (We add NUM_PINS to the
// enumeration so that we can tell how many pins there are.)
#undef PIN_ITEM
#define PIN_ITEM( Name, Enumeration ) Enumeration,
enum Pin_e { PINS_LIST NUM_PINS } ;



class Pin_c
{
public :
Pin_c( const char* Name )
: mName{Name}
{
// Nothing else to do in ctor
}

float GetVoltage() const
{
cout << "Dummy function to get voltage for pin " << mName << endl ;
return ( 0 ) ;
}

private :
string mName ;
} ;





int main( int argc, char *argv[] )
{


vector<unique_ptr<Pin_c>> Pins ;

for ( int ii = 0 ; ii < NUM_PINS ; ++ii )
{
unique_ptr<Pin_c> ThisPin{ new Pin_c{ PinNames[ii].c_str() } } ;
Pins.push_back( std::move(ThisPin) ) ;
}


// Access a couple of pins using their enumerations.
if ( Pins[ J1_A ]->GetVoltage() < Pins[J2_D]->GetVoltage() )
{
cout << "Pin J1_A voltage is less than J2_D voltage )" << endl ;
}
else
{
cout << "Pin J1_A voltage >= Pin J2_D voltage" << endl ;
}



return ( 0 ) ;
}






The define PINS_LIST is the full list of the the pins in terms of PIN_ITEM. Before using PINS_LIST I make sure that PIN_ITEM is suitable defined. This is done when we create the array of pin names PinNames and the enumeration for the pins Pin_e.

In the example the detail of the class Pin_c is not important, it is only there to show the kind of things I would like to do. The main function illustrates the kind of content a class that models a component would have. It would create pins, add them to a vector and access them using the Pin_e enumeration items.

So the discussion point is this "Is this a valid use of #defines in C++ or is there a better way to do this kind of thing?"

Any constructive comment is gladly welcomed!

Thanks in advance,

Andrew.

Continue reading...
 
Back
Top