Go Down

Topic: C++ templates (Read 9911 times) previous topic - next topic

aarondc

Something tells me I am going to have to specialise some templates where a memcopy is required to save the last println'd value of a variable. I can modify the comparison portion of the debug routine at the same time. I was considering comparing only a limited part of the value in that instance, although a strcmp makes the code look pretty minimal regardless.

Certainly nicer doing it this way than instantiating each version of the functions add / debug(var) / debug(name + var) by hand.
Windows serial port monitor: Tellurium | Arduino serial port debugging library: DBG | Cusom LCD char generator | Technical questions will only be answered in forum threads

Nick Gammon

Using void pointers, and memcpy, are basically side-stepping all of the type-checking that has been built into C over the years.

I'm wondering why you need to do this? I've seen threads before where people try to work around perceived language restrictions without stating what their true goal is. Once revealed, there is usually an easier way to do things.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

aarondc

I am storing references to variables in order to see if they have changed and act accordingly.
Windows serial port monitor: Tellurium | Arduino serial port debugging library: DBG | Cusom LCD char generator | Technical questions will only be answered in forum threads

aarondc

This site has been the pretty useful: http://www.cprogramming.com/tutorial/template_specialization.html

Partial template specialization. You can specify types but also values for the template. First time I saw that. That's really cool.

The example he provides

Code: [Select]
template <typename T, unsigned length>
class fixedVector { ... };


is immediately useful for my exercise. :D

That page also answers a question I had been considering, and already decided on the most logical answer.

Quote
A final implementation detail comes up with partial specializations: how does the compiler pick which specialization to use if there are a combination of completely generic types, some partial specializations, and maybe even some full specializations? The general rule of thumb is that the compiler will pick the most specific template specialization--the most specific template specialization is the one whose template arguments would be accepted by the other template declarations, but which would not accept all possible arguments that other templates with the same name would accept.
Windows serial port monitor: Tellurium | Arduino serial port debugging library: DBG | Cusom LCD char generator | Technical questions will only be answered in forum threads

Nick Gammon


I am storing references to variables in order to see if they have changed and act accordingly.


More detail?
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

aarondc



I am storing references to variables in order to see if they have changed and act accordingly.


More detail?


Start reading from Debugging library onwards: http://forum.arduino.cc/index.php?topic=169518.msg1261239#msg1261239

Windows serial port monitor: Tellurium | Arduino serial port debugging library: DBG | Cusom LCD char generator | Technical questions will only be answered in forum threads

aarondc

#21
Jun 21, 2013, 11:06 am Last Edit: Jun 21, 2013, 11:08 am by aarondc Reason: 1
For the people perhaps reading this thread who are actually interested in templates, or at least curious as to what they do, here's an example.

My old header file looked like this:

Code: [Select]

void addDebugVar(String, String&);
void addDebugVar(String, long&);
void addDebugVar(const __FlashStringHelper *, int&, int = false);
void addDebugVar(String, byte&, int = false);
void addDebugVar(String, int&, int = false);

void addDebugPin(const __FlashStringHelper *, int&);
void addDebugPin(String, byte&, int);
void addDebugPin(String, int&);
void addDebugPin(String, byte&);

void debug(String, String);
void debug(String, long);
void debug(String, byte);
void debug(const __FlashStringHelper *, int);
void debug(String, int);
  void debug(String &);
void debug(byte &);
void debug(long &);
void debug(int &);


The basic pattern of the functions is:

void [function name](<descriptive name of a variable>, <variable>); AND
void [function name](<variable>);

The <descriptive name of a variable> could be supplied as a String, or pointer to char, or F() macro, etc.
The <variable> could be any basic type, including - potentially - arrays.

The header file is obviously incomplete, as each function requires versions for the different <descriptive name of a variable> types, at least 2 of (char * and F()) and then a version of the function for each variable type people may be using. And I don't even know all the variable types! Then there are different functions (overloaded, of course) for handling whether the variable being added is a pin or a normal variable. etc, etc, etc.

The same header file, using templates, can be written as follows:

Code: [Select]

template <typename T1, typename T2>
void addDebugVar(T1, T2);

template <typename T1, typename T2>
void addDebugPin(T1, T2);

template <typename T1, typename T2>
void debug(T1, T2);

template <typename T1>
void debug(T1);


The beauty of this new header file, is that every possible combination of <descriptive name of a variable> type and <variable> type is generated for you, on the fly, based on usage of calls to those functions in the code. If you don't call that version of the function, it doesn't get compiled.

Very cool.

If this is old hat to you and you have a good website or ebook describing C++ templates, with examples, I really would appreciate a link!
Windows serial port monitor: Tellurium | Arduino serial port debugging library: DBG | Cusom LCD char generator | Technical questions will only be answered in forum threads

blckdmp

Bit of a dead thread, but if anyone's still reading it, I'd recommend www.learncpp.com .  Decent section on templates and very well written and approachable style to all the basic C++ concepts.
Cheers,
Jon


aarondc


Bit of a dead thread, but if anyone's still reading it, I'd recommend www.learncpp.com .  Decent section on templates and very well written and approachable style to all the basic C++ concepts.
Cheers,
Jon




Thanks for the heads up, much appreciated.

Windows serial port monitor: Tellurium | Arduino serial port debugging library: DBG | Cusom LCD char generator | Technical questions will only be answered in forum threads

SignalAudio

Hi there,

I have a question that particularly pertains to a couple of templates written by Nick Gammon, but I'll explain my scenario first.

I manufacture vision switcher control panels, originally based on Kasper Skaarhoj's fantastic work (we still collaborate on the libraries though they're still 99% his team's work).

My switchers run on the Mega 2560 with Ethernet (Freetronics EtherMega - specifically). I've optimised my libraries and menu code to a great extent and while I'm only about halfway through the program space, I'm running very lean on RAM.

A new model I'm developing includes a graphic OLED display, a big step up from the character OLED Parallel and more recently I2C displays I've been working with to date.

Graphic displays of this resolution (256x64) require a fairly large amount of memory to handle the character sets in different fonts and buffer etc; so my grand plan was to piggyback a second Arduino as a dedicated graphics processor. I've tested both I2C and SPI methods (from gammon.com.au - thanks Nick!) and have inter-arduino communication up and running, however this is where I've hit a template snag.

I would like to have the master send the slave a command string with a header that I'll parse in order to interpret the data that follows. For character displays, I've written into my libraries methods such as OLED.leftAlign(string,length,row,column), and on the graphic displays I'll need to send strings such as OLED.drawBox(topLeftX,topLeftY,bottomRightX,bottomRightY).

The forum page (http://www.gammon.com.au/forum/?id=10892) demonstrates how to send a string and how to send a range of other numeric data types; but I can't figure out how to get the template to accommodate both strings (or character arrays) as well as integers and floats.

I've tried reading up on templates, but I'm not getting far.

This the template library file from the forum at gammon.com.au:

Code: [Select]
#include <Arduino.h>

template <typename T> unsigned int SPI_writeAnything (const T& value) {
 const byte * p = (const byte*) &value;
     unsigned int i;
     for (i = 0; i < sizeof value; i++) SPI.transfer(*p++);
     return i;
}  // end of SPI_writeAnything

template <typename T> unsigned int SPI_readAnything(T& value) {
    byte * p = (byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          *p++ = SPI.transfer (0);
    return i;
  }  // end of SPI_readAnything
  
template <typename T> unsigned int SPI_readAnything_ISR(T& value) {
    byte * p = (byte*) &value;
    unsigned int i;
    *p++ = SPDR;  // get first byte
    for (i = 1; i < sizeof value; i++)
          *p++ = SPI.transfer (0);
    return i;
  }  // end of SPI_readAnything_ISR


Any help much appreciated !

Ta.
Signal Audio is a specialised event production company based in Melbourne, Australia.
Between events, I manufacture vision switcher control panels and coffee processing equipment.
instagram.com/signalaudio
roastiq.com.au

pYro_65

Quote
I can't figure out how to get the template to accommodate both strings (or character arrays) as well as integers and floats.
You'll need to use a char array, not a char* as only the array will contain size information. A pointer will send two bytes - the pointer address.

Sending an int or float should be straight forward. You shouldn't need to figure out the template, those functions are designed to accommodate different types without any extra effort on your part.
https://forum.arduino.cc/index.php?action=dlattach;topic=327736.0;attach=128670 New EEPROM library released

SignalAudio

Thanks pYro_65, these templates already accept int & float just fine; But while it does compile when I try char arrays, I don't get any output at the slave end (and not for ints or floats either, so I suspect it's breaking at the master end).

The method that Nick uses for char arrays is a bit different:
Code: [Select]
char c;
for (const char * p = "Hello, world!\n" ; c = *p; p++) SPI.transfer(c);


Obviously that example doesn't read an input but rather sends a specific string; but I thought perhaps I need an if statement within the template that checks typename and sends a char type to the above for loop.

I tried researching if statements within templates and pulled up short. A lot of talk about overloading vs specialisation etc, and some if statements that when I tried them wouldn't compile.

I don't think this template as it stands will accept char arrays.

Any ideas?
Signal Audio is a specialised event production company based in Melbourne, Australia.
Between events, I manufacture vision switcher control panels and coffee processing equipment.
instagram.com/signalaudio
roastiq.com.au

pYro_65

#27
May 02, 2016, 07:03 am Last Edit: May 02, 2016, 07:04 am by pYro_65
Quote
I don't think this template as it stands will accept char arrays.
Yes it does accept arrays.

You can verify it with this sketch. It is the same function modified for Serial instead of SPI:

Code: [Select]
template <typename T> unsigned int Serial_writeAnything (const T& value) {
 const byte * p = (const byte*) &value;
     unsigned int i;
     for (i = 0; i < sizeof value; i++) Serial.write(*p++);
     return i;
}

void setup() {

    Serial.begin(9600);

    char arr[] = "A test string";

    Serial_writeAnything(arr);

}

void loop() {}
https://forum.arduino.cc/index.php?action=dlattach;topic=327736.0;attach=128670 New EEPROM library released

PaulS

Quote
The forum page (http://www.gammon.com.au/forum/?id=10892) demonstrates how to send a string and how to send a range of other numeric data types; but I can't figure out how to get the template to accommodate both strings (or character arrays) as well as integers and floats.
You are having a hard time doing that because it is impossible. A template defines a cookie cutter class for ONE type, char array, int, int array, float, OR float array.

There is a type that you could use (struct) that allows combining data of different types. Then, the template would only need to deal with one type, which it can do.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy