Class-Instance as a constructor parameter

I built a class (eg.“DoInput”) with a pin-number in the constructor. No problem.

Now I want to use the library “DirectIO”, which uses class templates. Is it possible to do deliver the adress of an instance of DirectIO to the constructor? If this is not possible, the adress of the pinIn.read() function?

Like this:

#include <DirectIO.h>
Input<2> pinIn(INPUT_PULLUP);

class DoInput{
public:
    _type?_ myInput;
    DoInput(_type?_ myInput_) {
        myInput = myInput_;
    }
    void myfunc {
        ... myInput.read();
    }
};
DoInput doInput(*pinIn);

I’ve tried a lot variants for “type?”: e.g.
template Input* myInput; or just
Input *myInput;

but the tempate class is too tricky for me.

Thx, Norbert

Is it possible to do deliver the adress of an instance of DirectIO to the constructor?

Yes, but why would you want to? The (stupidly named) DoInput class needs an object, or a pointer to an object, not the address of the object.

The object that you want to pass to the construct is pinIn? That object has a type, Input.

Declare your constructor as taking an object, or pointer, of that type. I’d use a pointer, but, then I understand pointers.

Yes, I want to declare a constructor (and a variable) taking a pointer of the type Input* or Input* (not the address).
When I want to declare a pointer:

Input* myInput

the error message is:

type/value mismatch at argument 1 in template parameter list for ‘template class Input’

What is the correct type declaration?

Nobsi:
Yes, I want to declare a constructor (and a variable) taking a pointer of the type Input* or Input* (not the address).
When I want to declare a pointer:

Input* myInput

the error message is:

type/value mismatch at argument 1 in template parameter list for ‘template class Input’

What is the correct type declaration?

why are you not just using inheritance?

will a DoInput instance ever contain more than one DirectIO object?

Yes there will be some classes, some uses only one DirectIO-object, some are using 2 or 3. Input and Output mixed.

What is the correct type declaration?

Obviously something other than what you are using. If you really want help, you'll post all of your code and links to any libraries you didn't write.

Nobsi:
Yes there will be some classes, some uses only one DirectIO-object, some are using 2 or 3. Input and Output mixed.

what you are trying to do is not trivial.

Here is my highly reduced (and senseless) code.
The problem is the type of the pointer to the class instance of “Input”.

DirectIO, a very fast and small library (for me too complex), found on playground: https://playground.arduino.cc/Main/LibraryList
or directly from github: GitHub - mmarchetti/DirectIO: Fast, simple I/O library for Arduino

#include <DirectIO.h>

class DoInput{
public:
    Input<byte>* myInput;
    unsigned long cnt;

    DoInput(Input<byte> *myInput_) {
        myInput = myInput_;
        cnt=0;
    }
    void myfunc() {
        if ((*myInput).read()) cnt++;
    }
};

Input<2> pinIn;
DoInput doInput(*pinIn);

void setup() {
}

void loop() {
    delayMicroseconds(100); // delay makes no sense here, in real doing a lot of other things...
    doInput.myfunc();
}

If this will not work, I’ll try to set a pointer direct to the function “pinIn.read()” and put it into the constructor.

So, looking at the library source code, it looks like the template for the ‘Input’ class want a pin number as it’s parameter, like:

Input<2> pinIn;

So, it’s not clear to me what you want to happen when you give it a data type instead:

Input<byte>* myInput;

Also, this:

DoInput doInput(*pinIn);

Is calling your constructor with an argument that results from de-referencing your pinIn object. I can’t even imagine what that might be, but I’m pretty sure it’s not useful.

Finally, the constructor for the ‘Input’ class in the DirectIO library calls ‘pinMode()’ directly. I’ve heard that may not be the best thing to do.

Input<byte>* myInput;

In the words of the Mthbusters:

Well there’s your problem!

All template parameters must be specified or deducible at compile time. The Input class requires a uint8 as its template parameter. It requires a number, not a type.

The easiest way to fix this is to make your DoInput class a template as wall, and pass the pin number as a template parameter. That will prevent you from binding it to different pins at run time. That is part of the tradoff of doing direct I/O: flexibility is traded for speed.

If you must be able to change pins at runtime, another way is to rewrite the DirectIO classes to inherit from a non-template abstract class and take advantage of polymorphism. This reduces some of the benefit of a DirectIO library though, since virtual functions add some pointer dereferencing into the function calls, reducing performance.

Someone else already said it: This is not a trivial undertaking. You’ll really be exercising your class design skills with this.

How about rewriting DirectIO as a non-template class and then providing it with a begin() function that takes the pin number as an argument?

EDIT:
Never mind, looks like that could be a real PITA.

Thanks for your answers,
it seems to be difficult to put a template class in an other class' constructor. I'm not a c++ expert, so I will not rewrite the DirectIO-class.
OK, I made some wrong (de)referenced pointers in my example, but this is solvable for me. Thx, gfvalvo for your hints.
Maybe I'll try to make my own class as template - but I've to learn more of the template usage.

Otherwise I'll use the global instances of directIO directly in my class, with switch/case determination (OK, it's a dirty solution, but it will work and is fast enough).

Some of my DirectIO instances will be called during interupt routines, so they should be fast.

By the way: I also wondered the usage of pinMode in the constructor. But it worked in my case, and abviously also for the writer of DirectIO. Maybe the set of the propriate registers will survive all the other init processes. This is very helpful in my project with a lot of digital pins (half of my Mega pins are used). It's more clear to declare the variables and the state of the pins in the same place. During functional extensions of my sketch I sometimes forgot the use of pinMode....

Thx, Norbert

Nobsi:
it seems to be difficult to put a template class in an other class’ constructor, for example:

it isn’t difficult to create an object in the class:

#include "DirectIO.h"

class MyClass{
  public:
    Output<13> instance;
    void toggle(){
      instance.toggle();
    }
};

MyClass x;

void setup() {
}

void loop() {
  static uint32_t lastMillis = 0;
  if(millis() - lastMillis > 1000){
    lastMillis = millis();
    x.toggle();
  }
}

but I’d have to research how to instantiate an object using a constructor

Nobsi:
Thanks for your answers,
it seems to be difficult to put a template class in an other class’ constructor.

It’s not hard, you just need to know what to do. There are two things you can do:

  1. Fully specify the template parameters, like Bulldog’s suggestion.

  2. Make your “outer” class into a template itself, like this:

template<byte N>
class DoInput{
public:
    Input<N>* myInput;
    unsigned long cnt;

Jiggy-Ninja:
It’s not hard, you just need to know what to do. There are two things you can do:

  1. Fully specify the template parameters, like Bulldog’s suggestion.

  2. Make your “outer” class into a template itself, like this:

template<byte N>

class DoInput{
public:
   Input* myInput;
   unsigned long cnt;

Right!!!

example updated:

#include "DirectIO.h"

template<uint8_t N>
class MyClass{
  public:
    Output<N> instance;
    void toggle(){
      instance.toggle();
    }
  private:
};

MyClass<13> myClassObject;
Output<12> directIoObject;

void setup() {
  directIoObject = LOW;
}

void loop() {
  static uint32_t lastMillis = 0;
  if(millis() - lastMillis > 1000){
    lastMillis = millis();
    myClassObject.toggle();
    directIoObject.toggle();
  }
}

pointer version:

#include "DirectIO.h"

template<uint8_t N>
class MyClass{
  public:
    MyClass(){
      otherInstance = new Output<N>;
    }
    Output<N>* otherInstance;
    void toggleOther(){
      otherInstance->toggle();
    }
  private:
};

MyClass<13> myClassObject;
Output<12> directIoObject;

void setup() {
  directIoObject = LOW;
}

void loop() {
  static uint32_t lastMillis = 0;
  if(millis() - lastMillis > 100){
    lastMillis = millis();
    myClassObject.toggleOther();
    directIoObject.toggle();
  }
}

That's very simple. It's just the other way round to declare a directIO instance inside my classes. I'll play around a little with this, also with the pointer version.
I'm busy this Weekend so it will take some time...

Thx for your detailed answers! It's just copy&paste to test it :slight_smile:

I tested both methods in all my used classes, with one, two or three template parameters. It all works great and it’s simple. I used the version without pointer.
Now my code is more simple to read and digital IO is faster.

Thanks to all, you helped me a lot!
Norbert