Description
Just found this:
http://stackoverflow.com/questions/10044449/a-function-with-variable-number-of-arguments-with-known-types-the-c11-way
Add this to Print.h:
template <typename ...TailType>
size_t println(const String &head, TailType&&... tail)
{
size_t r = 0;
r+=println(head);
r+=println((tail)...);
return r;
}
Now you can do stuff like this:
Serial.println("Hey", "this", "is", "a", "Test");
Every word is printed in a new line. You can also add this for Serial.print (without newline).
Maybe this can be optimized to only print the last input with a new line. An overload with two arguments is needed here I guess.
Not sure if its perfect c++, but this would give us the option to print infinite strings at once.
Maybe one can generalize this even more to also print numbers (without formating of course, just DEC).
It takes a lot of flash though. But maybe someone can optimize this further? (Now that we also have c++11 with the merged PR)
Any comments on that?
Edit: Maybe this is also relevant. This uses the same size as if there was no template.
It can also handle numbers (without format).
https://msdn.microsoft.com/en-us/library/dn439779.aspx
template <typename First, typename... Rest>
inline size_t println(const First& first, const Rest&... rest) {
size_t r = 0;
r+=println(first);
r+=println(rest...); // recursive call using pack expansion syntax
return r;
}
Another example (ln now only adds a new line at the end):
template <typename First>
inline size_t println2(const First& first) {
return println(first);
}
template <typename First, typename... Rest>
inline size_t println2(const First& first, const Rest&... rest) {
size_t r = 0;
r+=print(first);
r+=println2(rest...); // recursive call using pack expansion syntax
return r;
}
Activity
NicoHood commentedon Jul 18, 2015
Seems I got it working pretty good:
Code to test:
Edit: One could also adapt this to other functions like:
pinMode(2,6,3,9,INPUT);
Edit2: Just a thought: Maybe we can also change the DEC, HEX, BIN into an enum and then be able to print 2 integers and a formatted integer at the same time. Maybe, not tested.
Chris--A commentedon Jul 19, 2015
At first glance, this seems like a great addition and I'm sure there are some further improvements we can look at. However this code will cause the current API to become C++11 only. Even if the code is wrapped in define guards, the reference will become separated unless a C++98 compatible version is provided using variadic functions.
Chris--A commentedon Jul 19, 2015
I do have an idea though! I give it a test when I'm home in a few hours.
q2dg commentedon Jul 19, 2015
Ooh, yeahh!! +1!!
NicoHood commentedon Jul 19, 2015
For some reason the print (without ln) has no higher priority on 1-2 function parameters. Meaning it will result in a loop and don't print anything. That is not a problem though, we can force the function to take at least 3 arguments to it wont bother at all. So if you input more than 2 args (>=3) it will print them in a row. No matter what type it is (int, float, String, char).
Formatted printing will not work I think.
I updated the code above. Should I create a PR to test this code?
Edit: @Chris--A Since we now have c++11, why not use it? I see no problem with that. Its enabled anyways.
NicoHood commentedon Jul 19, 2015
With the current pinMode layout it does not work with some overhead. At least I wasnt able to make it smaller. The problem is that the last argument is important for the other inputs. Here is a working, but more expensive example:
Chris--A commentedon Jul 19, 2015
I agree it should be used, however as it hasn't been released yet (an IDE with C++11 enabled) making the API version incompatible is quite restrictive. This should be discussed first I think (with the users, not dev team).
Many people chose to use the older IDE when breaking changes for IDE 1.0 were released, and subsequently many libraries written after 1.0 contained checks for WProgram.h to cater for the many people that used out dated third-party forks, or simply didn't want to upgrade.
Adding in this breaking change will prevent people from testing libraries/code for the older IDE's (by only a few months) and give many people further reason to not upgrade. As this code is just a convenience and doesn't allow a result that wasn't already possible, careful consideration should be put into this addition.
NicoHood commentedon Jul 19, 2015
Hum? C++11 is in the current 1.6.6 release merged.
This is a minor feature, nothing so much new. Its just a nice addition for the 1.6.x branch. Doesnt mean you cannot stick to the old version. And that there is a gap between 1.0.x and 1.6.x we already know and it will grow from update to update. That is progress in development. And this tiny addition shouldnt keep us from adding it.
They changed the whole USB core and I think this wasnt backported to 1.0.x, if they ever release 1.0.7. So the whole USB code will be more or less incompatible without some fixes. So I dont get the problem of adding this.
Chris--A commentedon Jul 19, 2015
The current release tag is 1.6.5, 1.6.6 hasn't been released. As minor as it is, if I enable gnu++98, the API no longer is compatible. It doesn't mean you can't use it, it means you cannot even compile the code.
At the very minimum, like the other C++11 code already implemented in the API, it should be disabled for C++98.
It should also be noted that many people can't use the latest releases due to their OS or other restrictions not supporting it (Mac has a minimum version now if I recall).
But either way, the code will eventually have to look at moving forward and forgetting the past, it just needs to be done carefully.
NicoHood commentedon Jul 19, 2015
I am working with the nightly build. And this has c++11 and 1.6.6 will also have c++11
Chris--A commentedon Jul 19, 2015
Yes, however this is not the point I'm arguing.
shiftleftplusone commentedon Jul 22, 2015
no idea if this helps, but:
for adding (concatenating) ANSI strings I'm using my own stradd() funktion:
Having this, you can concat a variable number of strings (tokens) to 1 long string and then do with the complete resulting string whatever you want.
OT:
the editor for posting (e.g., source code) is really a crap!
matthijskooijman commentedon Jul 23, 2015
@Chris--A, wrapping these methods in proper #ifdefs would solve the "it doesn't compile", I guess. But I'm not sure why this would be needed? Is there any good reason to disable C++11 mode for the Arduino core? There are probably other compiler flags that, if you change them, will break the compilation?
Another point that has not been mentioned is conflicts with the current
print()
methods. In particular the integer and float printing versions:Should this print "10016", or "64"?
It seems the conflict is minor, but I'm not sure which version will be favored by the compiler, and it is fundamental - if you have an any-number-of-arguments version, you can't really use extra arguments for specifying the formats.
It helps if you use markdown for your code blocks. I added ``` around it to make it a proper code block now.
NicoHood commentedon Jul 23, 2015
The current template above only works for >=3 parameters and wont do integer formating.
Meaning print(100, 16, 42); will give "1001642"
Otherwise we'd have to use enums for the HEX and DEC definitions and exclude the enums in the template (and I dont know how to do that or if its possible). Thatswhy the function is kept for >=3 args which should not conflict.
matthijskooijman commentedon Jul 23, 2015
I'm afraid that if
print("Hello", " ", "World")
works, butprint("Hello", "World")
does not, people will be terribly confused and this feature hurts more than it helps.Using enums for
HEX
etc. could help, but that won't help for theprint(float, precision)
version, where the precision is specified as a plain int instead of a constant...14 remaining items