C ++ Forced preprocessor for number estimation

I am writing a C ++ program and I have predefined objects Serial1, Serial2, Serial3, etc. I need to make a function to only work with one of them depending on the numeric input known at compile time. I am using the concatenation macro #define SER(x) Serial##x

, but in my case, if used SER(port).read()

and the port is an int equal to 1, the expression expands to Serialport.read()

instead of Serial1.read()

. However, SER(1).read()

it gives the desired result. How do I make the preprocessor evaluate a variable port

and use its value in the extension?

BTW, I don't know the class name Serial1, Serial2, etc., so I can't work out a workaround using pointers or references

EDIT: After looking at some of the answers, I need to add some clarification. I need to be able to use this function with all Serial1, Serial2, etc. by calling it multiple times in the SINGLE RUN of my code. Sorry for not understanding this sooner!

+3


source to share


2 answers


You need to use two levels of macros to accomplish what you are trying.

#define SER2(x) Serial##x
#define SER(x) SER2(x)

      

Here is a test program demonstrating the concept.

#include <iostream>
#include <string>

struct Port
{
   Port(std::string name) : name_(name) {}

   void write()
   {
      std::cout << name_ << std::endl;
   }

   std::string name_;
};

Port Serial1("PORT1");
Port Serial2("PORT2");

#define SER2(x) Serial##x
#define SER(x) SER2(x)

int main()
{
   SER(port).write();
}

      


Build command:

g++ -std=c++11 -Wall    socc.cc   -o socc -Dport=1

      

Output:



PORT1

      


Build command:

g++ -std=c++11 -Wall    socc.cc   -o socc -Dport=2

      

Output:



PORT2

      

Update

In the updated question, the only sane approach is to use an array of objects and use the appropriate array element based on runtime data.

+2


source


The fact that you don't know the type doesn't really matter: decltype(Serial1)

will give this. Do you know if they are all the same types? Because if they don't, no C ++ function can return them directly. And if they don't even have a common base class, it's even more difficult.

The template engine is more powerful than the preprocessor, so it makes sense to do this:

template<int N> struct Serial { };
template<> struct Serial<1> { static decltype(Serial1)* const ptr = &Serial1 };
template<> struct Serial<2> { static decltype(Serial2)* const ptr = &Serial3 };
template<> struct Serial<3> { static decltype(Serial3)* const ptr = &Serial3 };

// You can now use Serial<8/2-2>.ptr->

      



Of course, writing out specialized templates is boring. So let Boost.PP:

#define BOOST_PP_LOCAL_MACRO (1, 7) // Assuming you have ports 1 to 7
#define BOOST_PP_LOCAL_MACRO(n) \
   template<> struct Serial<n> { \
       static decltype(BOOST_PP_CAT(Serial,n))* const ptr = &Serial##n; \
   };
#include BOOST_PP_LOCAL_ITERATE()

      

Yes, the last line is #include

without quotes. And no, I'm not sure if this is an improvement;)

+2


source







All Articles