Simple template functions?

I’d like to have a Print function that acts like Serial.print, but can internally be set to not print anything.
Basically if DEBUG_OUTPUT is set to false, the new Print function should not print anything.

I imaged it somewhat like this:

const bool DEBUG_OUTPUT = true;
template <typename any>
void Print( any data, int base = DEC ) {
 if (DEBUG_OUTPUT)
     Serial.print(data, base);
}

template void Print<>(const __FlashStringHelper *);
template void Print<>(const String &);
template void Print<>(const char[]);
template void Print<>(char);
template void Print<>(unsigned char, int);
template void Print<>(int, int);
template void Print<>(unsigned int, int);
template void Print<>(long, int);
template void Print<>(unsigned long, int);
template void Print<>(double, int);
template void Print<>(const Printable&);

Since Serial.print accepts all sorts of different data types I tried to create a function template that can atke the same datatypes listed in C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\Print.h

But I get a ton of different errors. So I think there is something fundamentally wrong with my approach.

Any ideas?

You can achieve this properly with two discrete functions, one for a single parameter and the other for two. You do not need to specialize for each type as this is what the template is essentially doing for you.

Also you need to add the prototypes as the IDE, depending on which version, will either have a tantrum, or not generate any prototype for you.

template< typename T, typename U > void Print( T data, U modifier );
template< typename T > void Print( T data );

const bool DEBUG_OUTPUT = true;

template< typename T, typename U > void Print( T data, U modifier ){
    if(DEBUG_OUTPUT)
     Serial.print(data, modifier);
  }
template< typename T > void Print( T data ){
    if(DEBUG_OUTPUT)
     Serial.print(data);
  }

It may be beneficial to make the functions inline, just do some testing.
Also ensure DEBUG_OUTPUT is always a compile time constant so when its not used the functions do not generate any code at all.

Also you’ll need to change the name.

The name ‘Print’ will cause conflicts with the actual ‘Print’ class. And printable classes. E.g.

Using the functions I posted above, this goes kaboom as it expects a class ‘Print’ in the printTo function, but it is seen as a function.

#include <IPAddress.h>

void setup() {
  IPAddress a;
  Print( a );
}

Pick something closer to its function like ‘PrintDbg’ or even use a lower case ‘print’, just not ‘Print’

#ifdef DEBUG
#define log(s) Serial.print(s)
#define logln(s) Serial.println(s)
#else
#define logln(s)
#define log(s)
#endif

be careful never to put anything in your logs that have side effects (assignments, function calls that affect state).

// DebugMacros.h

/* Example of use:
   #define DEBUG          // <-----<<<< this line must appear before the include line
   #include <DebugMacros.h>
*/

//If you comment the line:  #define DEBUG
//The Macro lines are defined as blank, thus would be ignored by the compiler.
//If the line is NOT commented, these macros will be included in the sketch.
// examples:
// This  converts to         >>>>----->         This OR a Blank Line. 
//---–----------------------------------------------------------------------------------------
// DPRINTLN("Testing123");   >>>>----->     Serial.println("Testing123"); 
// DPRINTLN(0xC0FFEEul,DEC); >>>>----->     Serial.println(0xC0FFEEul,DEC);
// DPRINTLN(12648430ul,HEX); >>>------>     Serial.println(12648430ul,HEX);
// DPRINTLNF("This text came from flash");  Serial.println(F("This text came from flash"));
// DPRINT(myVariable);       >>>>----->     Serial.print(myVariable);
// DELAY(100);               >>>>----->     delay(100);
// SERIALBEGIN(9600);        >>>>----->     Serial.begin(9600);
// PINMODE(13,OUTPUT);       >>>>----->     pinMode(13,OUTPUT);
// TOGGLEd13;                >>>>----->     PINB = 0x20;  // D13 Toggle,for UNO ONLY
 
#ifdef DEBUG
//#define DPRINT(args...)  Serial.print(args)             //OR use the following syntax:
#define SERIALBEGIN(...)   Serial.begin(__VA_ARGS__)
#define DPRINT(...)        Serial.print(__VA_ARGS__)
#define DPRINTLN(...)      Serial.println(__VA_ARGS__)
#define DRINTF(...)        Serial.print(F(__VA_ARGS__))
#define DPRINTLNF(...)     Serial.println(F(__VA_ARGS__)) //Printing text using the F macro
#define DELAY(...)         delay(__VA_ARGS__)
#define PINMODE(...)       pinMode(__VA_ARGS__)
#define TOGGLEd13          PINB = 0x20                    //For the UNO only
 
#else
#define SERIALBEGIN(...)   //blank line
#define DPRINT(...)        //blank line
#define DPRINTLN(...)      //blank line
#define DPRINTF(...)       //blank line
#define DPRINTLNF(...)     //blank line
#define DELAY(...)         //blank line
#define PINMODE(...)       //blank line
#define TOGGLEd13          //blank line 
 
#endif
//***************************************************************

If your using Serial only for debugging. This bit of code simply removes Serial completely from your program when set false

#define DEBUG false                         // Set to true to enable Serial Debug
#define Serial if (DEBUG)Serial            // WARNING: Use only when Serial is used for Debugging only (THIS REMOVES Serial COMPLETELY!!!)
1 Like