2

I'd like to write a function like this:

void lcdPositionPrint(int row, int col,  content) {
    lcdPosition(row, col);
    LCD.print(content);
}

but I'm not certain how to declare "content", because it might be a string, or an int, or who knows what, just as it is for the "Serial.print" function or the LCD.print() function. Is there an easy way to do this?

2 Answers 2

1

There isn't really a great way to do it, but there are a few ways to get it to work. Most of the problem here is that there is actually a different LCD.print function for every data type. You aren't really calling the same function, your calling different functions that share the same name.

You could use templates. They are a powerful system built into C plus plus for generating functions and avr-gcc supports them well. With them, you can make the compiler generate all the necessary versions of your function for you. Your function would then look like this:

template<typename T>
void lcdPositionPrint(int x, int y, T content) throw() {
  lcdPosition(row, col);
  LCD.print(content);
}

That part about throw() isn't doing anything except keeping the ".ino" preprocessor from messing the template function up. You can call the templated function like normal, or with an explicit type

lcdPositionPrint(0,0,"hello");
lcdPositionPrint<float>(0,0,32.0f);

You could also use the preprocessor. Your function is very simple, so you could just as easily make it a preprocessor macro that just places you code you want in the file whenever your "function call" appears. It looks like this:

#define lcdPositionPrint2(row,col,content) \
    do { lcdPosition(row, col); LCD.print(content); } while (0)

The \ there tells the preprocessor that the next line is also part of the macro, and you will need one on every line but the last of your function. Wrapping it in a do loop that immediately ends makes it nicely substitute into more situations. Micros don't scale up well, but they are a bit simpler for quick debugging situations. The code is duplicated in each call location instead of being bundled into functions though.

3
  • Thanks; I didn't know that templates existed in the language. (To be honest, although I've written a few hundred lines, I've never been clear on what language I'm using -- I just kinda wing it). My own solution was to write two near-identical copies, one for "int content" and one for "String content", and that covered all my bases.
    – John
    May 21, 2015 at 10:22
  • 1
    One more thought: an improved version of your preprocessor solution puts braces around the {lcdPosition(row, col); LCD.print(content);} lines so that "if (x < 10) lcdPositionPrint(r, c, 14); <other code>" doesn't always end up printing "14", either at (r, c) or at the current cursor location.
    – John
    May 21, 2015 at 10:25
  • 1
    That's what wrapping it in do { ... } while (0) is for (and all of the other issues that can show up when just using braces). May 21, 2015 at 16:53
1

One way to do this is to use generics. And we also need to use an unnamed namespace to get around the IDE's "helpfulness":

namespace {
    template<typename T>
    void lcdPositionPrint(int row, int col, T content) {
        lcdPosition(row, col);
        LCD.print(content);
    }
}

This will cause the compiler to create one function for each type passed in content that the function is actually called with.

1
  • Thanks very much. I didn't know that there were templates to work with!
    – John
    May 21, 2015 at 10:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.