[Example] C++ lambda and function tables

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are a lot of lambda examples on the web but I couldn't find one that explained what I wanted to do. So after a lot of trial and error this is what I came up with so far. Here is an example of using a lambda with an array of function pointers.

namespace foo {

uint8_t bar(uint8_t xyz) {return xyz +1;}
uint8_t baz(uint8_t xyz) {return xyz +2;}
}
namespace dog {

uint8_t fido(uint8_t xyz)  {return xyz +3;}
uint8_t sparky(uint8_t xyz){return xyz +4;}
}

typedef uint8_t (*FnPtr) (uint8_t c);
uint8_t (*table[])(uint8_t c)= {foo::bar,foo::baz,dog::fido,dog::sparky};

int main()
{
   volatile uint8_t arg;
	uint8_t cmd = 0;

	
	do
	{

		auto lambda_fn = [&table](uint8_t c) -> FnPtr { return table[c]; };
		
		(lambda_fn(cmd))(arg);
		
		if (3 > cmd)
			++cmd;
		else
			cmd = 0;

	}while (1);

	return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting example! I am used to using lambdas in other languages so I've been watching their inclusion into C++ closely. Think I'm going to have to spend some more time with the syntax - I can't just read it without effort yet!

What version of gcc are you compiling this with?

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice example John.

I have noticed that Cliff (clawson) has mentioned, in several posts lately, the problem of code readability due to some form of clever, or experience driven, coding method used by the coder. I am certainly guilty of doing that myself.

While the code

      if (3 > cmd) 

is perfectly correct, for interests of code readability, the following code might be more appropriate.

      if (cmd < 3) 

What this comparison is doing would certainly be easier for less experienced coders to understand, though I doubt that less experienced coders would understand any of the example code you provided at all.

Personally, I like the code the way it is written as it demonstrates a way to "think outside of the box".

Keep up the good work.

EDIT: Changed <= to < per Martin's reminder below.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Wed. Jun 29, 2011 - 11:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckeemj wrote:
Interesting example! I am used to using lambdas in other languages so I've been watching their inclusion into C++ closely. Think I'm going to have to spend some more time with the syntax - I can't just read it without effort yet!

What version of gcc are you compiling this with?

Martin Jay McKee

Yeah, I'm trying to get used to the syntax. Even with examples I was having a hard time getting it to work.

I'm using (AVR_8_bit_GNU_Toolchain_3.2.3_314) 4.5.1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually, in this case there is a good argument for the code being the way it is.

if (3 > cmd)

and ( Note: this excludes three ),

if (cmd < 3)

are, indeed, identical. However,

if( 3 = cmd )

and,

if( cmd = 3 )

are not. In the first case the compile will give an error because 3 ( an int ) is not an lvalue; in the second case the compiler will, at most, give a warning. In both of these cases, of course, it is more likely that the programmer meant to use ==, i.e.

if( 3 == cmd )
// or
if( cmd == 3 )

Using the constant first enforces the use of comparison operators in place of possible assignment operators. As such, it can help to find coding errors where as the more "typical" method does not.

Having said all that, I still use the "typical" way - force of habit.

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckeemj wrote:
Actually, in this case there is a good argument for the code being the way it is.
if (3 > cmd)

and ( Note: this excludes three ),

if (cmd < 3) 

are, indeed, identical...

Having said all that, I still use the "typical" way - force of habit.


Thank you Martin, I've edited my code above. I use the "typical way" too for the same reason.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've worked with a coding standard that mandated putting the literal on the left. I totally understand why it's better but it doesn't feel right - a bit "forthish" I guess?

(I have a sneaking suspicion that MISRA may mandate it too).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

a coding standard that mandated putting the literal on the left. I totally understand why it's better

I think that having the literal on the left looks awful. It is completely non-intuitive, e.g. w r t mathematical notation.

I'd much prefer if there was a compiler option to prevent assignments in the conditionals of selection- and iteration-statements. Or a LINT that can catch it?

I took a quick tour in the MISRA C document, and I could not spot any "literal to the left"-rule.

There is a rule (effectively) preventing assignment in conditionals. (For those with access to a MISRA document, I am referring to rule 13.1.)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
There is a rule (effectively) preventing assignment in conditionals. (For those with access to a MISRA document, I am referring to rule 13.1.)
I don't have access to the standard but it would seem that such a rule would also preclude the use of ++ and -- in conditional expressions leading to code duplication and multiple maintenance issues.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

While I can agree with it making the code less "terse" (putting no opinion into that word here), I can't see how it is

Quote:
leading to code duplication and multiple maintenance issues

Example?

How would e.g.

i++;
if (i > 5)...

instead of

if (++i > 5)...

lead to this?

(Well, unless you concider having to use the variable name twice instead of once an example of "code duplication". With any reasonably modern editor this would still not lead to "multiple maintenance issues", since the only issue that could surface is renaming the variable, and any reasonably modern editor supports "rename refactoring". :wink:)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Example?
Where post increment/decrement is needed you either need to introduce a temporary variable or duplicate the post increment/decrement.
// if this isn't allowed by MISRA
if (a++ < 5)
{
  // do this
}

// then you have to do this
if (a < 5)
{
  a++;
  // do this
}
else
{
  a++;
}

// or, alternately
uint16_t temp;
temp = a++;
if (temp < 5)
{
  // do this
}

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I've worked with a coding standard that mandated putting the literal on the left. I totally understand why it's better but it doesn't feel right - a bit "forthish" I guess?

Cliff, it is not quite reverse postfix notation but does seem a little like Forth. Although it would be written as "3 variable >".
clawson wrote:

(I have a sneaking suspicion that MISRA may mandate it too).

I hope not, and as Johan has said it appears not to be the case. MISRA = miserable.

On the issue of the literal on the left, leave it up to the coder to use what he feels more comfortable with and have the compiler issue an error when an assignment is done in a conditional expression.

Would MISRA let me use statements like this?

   if ((nextpinstate = !nextpinstate)) { // I know this is funky but it works well 

I know I shouldn't be writing code like that in the first place. :)

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Would MISRA let me use statements like this?

I don't know but I'd hope a good software manager wouldn't. Remember you are writing the code for the next reader. So do not employ "smart" tricks that reduce the readability.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Would MISRA let me use statements like this?
Code:

if ((nextpinstate = !nextpinstate)) { // I know this is funky but it works well


I'm not at the machine with the MISRA stuff right now, and my memory is short, but IIRC the rule was formulated something along the lines of "No 'boolean expression' may also involve an assignment". (In a Glossary appendix, the MISRA document correctly identifies that there is no boolean type in C, and explain what they mean with the formulation).

So no, that would not pass the MISRA rule.

And no, that would not pass me either.

As long as there are no hard performance requirements (speed, size) code should always be written to optimize for maintenance of it. I.e. always write code as straight-forward, non-intricate and apparently non-ambiguous as you can.

In my eyes, that code is funky and works quite bad in this respect.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I find this MISRA summary useful:

http://computing.unn.ac.uk/staff...

Quote:
35 (req):
Assignment operators shall not be used in expressions that return Boolean values

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff!

I can't help to wonder if that document breaks MISRAs copyright on their documents...

As I said, I'm not on the computer where I keep my copies of the MISRA C and C++ documents, so I can not quote the copyright notice. But I know that when you buy the documents you get personalized documents with your name on every page.

But yes, that is the rule I was referring to.

Don! I see your point. But I also see that I need to think several times about the

if (a++ < 5) 

to be sure in what order "stuff happens", and I find such code disturbing. It is a rather theoretical example (though illustrating your point excellently) and for a "real world example" I would try to express it in another way. But yes, I see your point.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I appreciate your comments guys.

After having used that, as an example for someone else, I decided it was not only "funky" it was awful. That is why I made the comment:

larryvc wrote:
I know I shouldn't be writing code like that in the first place. :)

I changed it to:

    if (nextpinstate == 0) {
       do stuff
    else {
       do other stuff
    }
    nextpinstate = !nextpinstate;

Cliff, I have taken your code readability suggestions very seriously. I usually never write code like that, why I did it in that instance was "funky". :?

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius