Arduino IDE support for C++ (getting Boost library to work with Arduino)

I am trying to learn more about C++ object-oriented programming by re-writing some parts of my code using classes. One of my classes looks like this:

class potentiometer
{
    using read_function_t = std::function< int(byte) >  ;
    byte pinNum;
    read_function_t readFunction ;

    public:
        potentiometer( byte, read_function_t fun );
        int analogRead(); // analogreads the pot
};

The compiler barfs on the “using read_function_t” line, as well as its “typedef” equivalent, but I’m pretty sure the syntax is correct. When I look up references on polymorphic function wrappers, they all seem to say, “since C++11”, and that makes me wonder whether the issue is that the Arduino IDE doesn’t use C++11 by default (Google seems to say that it doesn’t), and whether that is the issue.

Given all that, what would be the suggested approach? Is there a pre-C++11 method of accomplishing the same thing as polymorphic function wrappers?

For those who may want a little more context, and who may be wondering why I don’t just use analogRead() to read the pot, the reason is that the pot may be hooked up to a mux, for example, in which case the function to read the pot would be AnalogMux::AnalogRead() instead of analogRead(), so I wanted to be able to instantiate the pot with a pointer to a unique function that would be used to read the pot, so that any special circumstance of needing to read the pot would be handled.

EDIT: My version of avr-g++ is 4.3.2, and apparently you need at least 4.7 to do C++11 stuff.

Continued research seems to indicate that the boost library is the answer to using this functionality pre-C++11. Looking into Arduino support for that now...

Making some progress. Downloaded the boost and the standardCplusplus libraries and installed them. Current code is:

#include <StandardCplusplus.h>
#include <boost_1_51_0.h>
#include "analogmuxdemux.h"

class potentiometer
{
    // http://www.boost.org/doc/libs/1_54_0/doc/html/function.html
    typedef boost::function< int(byte) > read_function_t ; // alternate syntax

    byte pinNum;
    read_function_t readFunction ;

    public:
        potentiometer( byte, read_function_t fun );

        int analogRead(); // analogreads the pot
};

potentiometer::potentiometer( byte pin , read_function_t fun )
{
  pinNum = pin ;
  readFunction = fun ;
}

int potentiometer::analogRead()
{
  return readFunction(pinNum);
}

int non_member_AnalogRead( byte pin )
{
    std::cout << "non_member_AnalogRead: pin == " << int(pin) << '\n' ;
    // read
    return 0 ;
}

void setup() {
}

void loop () {
}

This produces output:

C:\Program Files\Arduino\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=105 -IC:\Program Files\Arduino\hardware\arduino\cores\arduino -IC:\Program Files\Arduino\hardware\arduino\variants\standard -IC:\Users\Bardwell\Dropbox\Arduino\libraries\standardcplusplus -IC:\Users\Bardwell\Dropbox\Arduino\libraries\boost_1_51_0 -IC:\Users\Bardwell\Dropbox\Arduino\libraries\arduino_analog_multiplexer_master C:\Users\Bardwell\AppData\Local\Temp\build4392647147001728539.tmp\welder_pedal_output_OO.cpp -o C:\Users\Bardwell\AppData\Local\Temp\build4392647147001728539.tmp\welder_pedal_output_OO.cpp.o 
welder_pedal_output_OO:8: error: 'boost' has not been declared
welder_pedal_output_OO:8: error: ISO C++ forbids declaration of 'function' with no type
welder_pedal_output_OO:8: error: typedef name may not be a nested-name-specifier
welder_pedal_output_OO:8: error: expected ';' before '<' token

So I can see that it is finding the library, but it still seems not to be recognizing the boost:: object.

You can do this without using the boost library.

typedef int (*read_function_t)(byte);
class potentiometer
{
    byte pinNum;
    read_function_t readFunction ;

    public:
        potentiometer( byte, read_function_t fun );

        int analogRead(); // analogreads the pot
};

I tried that, but the problem (as I understand it) is that you can't mix a member-function pointer and a global-static-function pointer. So when I tried to instantiate a potentiometer object as such:

AnalogMux aMux(1, 2, 3, A0);
potentiometer(pinNum, aMux.AnalogRead);

It barfed. It worked fine with:

potentiometer(pinNum, analogRead);

Because analogRead() is a global, static function. But the desired functionality is to be able to instantiate a potentiometer and to have that potentiometer object know what function it needs to use to read itself, whatever function that might be.

Ah, got you.

You could make it work with the AnalogMux library specifically, but I don't think that is what you want either.

typedef int (AnalogMux::*read_function_t)(byte);
class potentiometer
{
    byte pinNum;
    read_function_t readFunction ;
    AnalogMux* theMux

    public:
        potentiometer( byte, read_function_t fun, AnalogMux* mux);

        int analogRead(); // analogreads the pot
};

potentiometer::potentiometer( byte pin , read_function_t fun, AnalogMux* mux)
{
  pinNum = pin ;
  readFunction = fun ;
  theMux = mux;
}

int potentiometer::analogRead()
{
  return (theMux->*readFunction)(pinNum);
}

Any you'd do:
potentiometer(pinNum, aMux.AnalogRead, &aMux);

Right. Because that requires that the pot include a mux, and what I'd like, conceptually, is to have the mux object and the potentiometer objects to be distinct. A pot knows its pin-number and knows how to read itself. A mux knows other things. Also, it's possible that there would be some other way of reading a pot, such as... I don't know... an I2C digital pot, in which case the analogRead() function would do something else entirely. And I don't think it makes good sense to have to constantly re-define the potentiometer object for each type of read() function you might want to call.

I mean, I'm still brand new to OO design, but that's the way that seems "right" to me.

You're going to have to bridge the gap between good OO design and the Arduino runtime, because Arduino isn't very OO. I'd have thought the OO answer would be to define an interface which represented a source of analog values and use that in the class that needs to get analog values. Then you can compose your object using whichever type of analog source is applicable. In other words use an interface, not a function pointer.

PeterH:
You're going to have to bridge the gap between good OO design and the Arduino runtime, because Arduino isn't very OO.

I dunno. I just figured all the libraries are written with classes, so I assumed everybody else out there who was a "real" coder was writing Arduino programs using classes.

I'd have thought the OO answer would be to define an interface which represented a source of analog values and use that in the class that needs to get analog values. Then you can compose your object using whichever type of analog source is applicable. In other words use an interface, not a function pointer.

I'll look into that.

Okay. I studied up on interfaces, and this is what I came up with. It would make more intuitive sense to me if it was a single class that could take a function pointer as an argument, but this isn't too bad.

#include "analogmuxdemux.h"

/*************************************************************************************
  Analog input class
  ************************************************************************************/

class analogInputBase {
protected:	
  byte pinNum; // pin number on which the input is read
public:
  analogInputBase(byte);
  virtual int analogRead() =0;
};

analogInputBase::analogInputBase(byte p) {
  pinNum = p;
}

/*************************************************************************************
  Analog output class
  ************************************************************************************/

class analogOutputBase {
protected:	
  byte pinNum; // pin number on which the input is read
public:
  analogOutputBase(byte);
  virtual int analogWrite() =0;
};

analogOutputBase::analogOutputBase(byte p) {
  pinNum = p;
}


/*************************************************************************************
  Potentiometer classes
  ************************************************************************************/

class potentiometer : public analogInputBase {
public:
  potentiometer(byte);
  int analogRead();
};

potentiometer::potentiometer(byte p) : analogInputBase(p) {
  // call base class constructor--that's all
}

int potentiometer::analogRead() {
  return ::analogRead(pinNum); // calls the system analogRead to read directly from an input pin
}

class muxedPotentiometer : public analogInputBase {
  AnalogMux *aMux;
public:
  muxedPotentiometer(byte, AnalogMux*);
  int analogRead();
};

muxedPotentiometer::muxedPotentiometer(byte p, AnalogMux *a) : analogInputBase(p) {
  aMux = a;
}

int muxedPotentiometer::analogRead() {
  return aMux->AnalogRead(pinNum);
}

/*************************************************************************************
  Digital input class
  ************************************************************************************/

class digitalInputBase {
protected:	
  byte pinNum; // pin number on which the input is read
  virtual byte digitalRead() =0;
public:
  digitalInputBase(byte);
};

digitalInputBase::digitalInputBase(byte p) {
  pinNum = p;
  pinMode(p, INPUT_PULLUP);
}

class button : public digitalInputBase {
  byte digitalRead();
public:
  button(byte);
  boolean isPressed(); 
};

button::button(byte p) : digitalInputBase(p){
  // call base class constructor -- that's all
}

byte button::digitalRead() {
  return ::digitalRead(pinNum);
}

boolean button::isPressed() {
  return digitalRead() == LOW;
}

/*************************************************************************************
  Digital output class
  ************************************************************************************/

class digitalOutputBase {
protected:	
  byte pinNum; // pin number on which the input is read
  virtual byte digitalRead() = 0;
  virtual void digitalWrite(byte) = 0;
  virtual void analogWrite(int) = 0;
public:
  digitalOutputBase(byte);
};

digitalOutputBase::digitalOutputBase(byte p) {
  pinNum = p;
  pinMode(p, OUTPUT);
}

/*************************************************************************************
  LED class
  ************************************************************************************/

class led : public digitalOutputBase {
  void digitalWrite(byte);
  byte digitalRead();
public:
  led(byte);
  void analogWrite(int);
  boolean isTurnedOn();
  void turnOn();
  void turnOff();
};

led::led(byte p) : digitalOutputBase(p) {
  // call base class constructors -- that's all!
}

void led::digitalWrite(byte b) {
  ::digitalWrite(pinNum, b);
}

byte led::digitalRead() {
  return ::digitalRead(pinNum);
}

void led::analogWrite(int i) {
  ::analogWrite(pinNum, i);
}

boolean led::isTurnedOn() {
  return digitalRead() == HIGH;
}

void led::turnOn() {
  digitalWrite(HIGH);
}

void led::turnOff() {
  digitalWrite(LOW);
}

... you know, it occurs to me that if I continue down this road, I'll end up writing Arduino code that nobody else on the Internet can easily read or debug. For example, instead of calling pinMode() inside setup(), I'll just instantiate a potentiometer object, and the pinMode will be called in the object's constructor--but that won't be where people will expect it to be. It looks like I would have to start by basically wrapping all of the Arduino system functions inside an OO shell, more or less totally reinventing the syntax of the IDE. To what end, I'm not sure...

joshuabardwell:
When I look up references on polymorphic function wrappers, they all seem to say, "since C++11", and that makes me wonder whether the issue is that the Arduino IDE doesn't use C++11 by default ...

It doesn't as far as I know. It uses C++.

Make a glue routine. This is nice and simple:

typedef int (*read_function_t)(byte);
class potentiometer
{
    byte pinNum_;
    read_function_t readFunction_;

    public:
        potentiometer( byte, read_function_t fun );

        int analogRead(); // analogreads the pot
};

potentiometer::potentiometer (byte pinNum, read_function_t fun)
  {
  pinNum_ = pinNum;
  readFunction_ = fun;
  }
  
// glue
int myRead (byte foo)
  {
  return Serial.read ();
  }
  
potentiometer pot (15, myRead);

void setup () { }
void loop () { }

joshuabardwell:
For example, instead of calling pinMode() inside setup(), I'll just instantiate a potentiometer object, and the pinMode will be called in the object's constructor--but that won't be where people will expect it to be.

Plus there's the "static initialization order fiasco".

http://www.parashift.com/c++-faq/static-init-order.html

I wouldn't advise calling pinMode in a constructor.

My advice would be to not use the C++11 stuff.