error: '((MyClass*)this)->MyClass::tReadSensors' does not have class type

After a few hours of googling I’m still at a loss on how to make this work.

It’s a class, and the Scheduler is from the separate TaskScheduler library. This object is instantiated in the main sketch and then passed into my library.

I’m trying to call a member function from this Task object, and that’s where the compiler throws an error (see below). I’m completely at a loss how to make it work.

The .h file:

#ifndef HYDROMONITORMASTER_H
#define HYDROMONITORMASTER_H

#include <TaskScheduler.h>


class HydroMonitorMaster 
{
  public:
    HydroMonitorMaster();
    void begin(Scheduler);
  
  private:
  
    // The task scheduler.
    Scheduler ts;
    Task tReadSensors(int, int, void (HydroMonitorMaster::*)(), Scheduler*, bool);
    void readSensors(void);

};
#endif

The .cpp file:

#include <HydroMonitorMaster.h>


HydroMonitorMaster::HydroMonitorMaster() {
}

void HydroMonitorMaster::begin(Scheduler t) {

  // f is the task scheduler object, we use this to set up all the repeating tasks.
  ts = t;
  tReadSensors (10*1000, TASK_FOREVER,  &HydroMonitorMaster::readSensors, &ts, false);
  tReadSensors.enable();
}

void HydroMonitorMaster::readSensors() {
  // Go and read the sensors.
  
}

The .ino sketch (yes, this is the complete sketch that I use to compile this library - the real thing is of course a lot longer but the error doesn’t change stripping it down to this):

#include <HydroMonitorMaster.h>

And finally the error when trying to compile this:

/home/wouter/Arduino/libraries/HydroMonitor/src/HydroMonitorMaster.cpp: In member function 'void HydroMonitorMaster::begin(Scheduler)':
/home/wouter/Arduino/libraries/HydroMonitor/src/HydroMonitorMaster.cpp:12:15: error: '((HydroMonitorMaster*)this)->HydroMonitorMaster::tReadSensors' does not have class type
   tReadSensors.enable();
               ^
exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).

One, you are creating a lot of new objects of scheduler. Did you mean to create references?

And why is the Scheduler created in the sketch?

And where is tReadSensors defined?
Missed it, one moment please :stuck_out_tongue:
No, didn't miss it. You do make function declaration but you never define it.

And what do you try to do when you call a method on a method reference...

tReadSensors.enable();

And edit x:
What is the scope operator doing in the method declaration?

This is basically copy/pasted from my original sketch in an attempt to convert it into a library (and make it reusable for other very similar projects), where it works just fine.

The TaskScheduler is this one: Arduino Playground - TaskScheduler

I've followed their examples to create all these Task objects. Each Task is a process that has to be run periodically. The .enable() call is to start running this task. There are a few more methods to these Task objects that I didn't use in this smallest possible example, this is also just one of several Task object that operate the final thing.

wvmarle:
This is basically copy/pasted from my original sketch in an attempt to convert it into a library (and make it reusable for other very similar projects), where it works just fine.

Show it! :slight_smile:

wvmarle:
I've followed their examples to create all these Task objects. Each Task is a process that has to be run periodically.

But you're creating more (local) objects than you might think...

wvmarle:
The .enable() call is to start running this task.

Small hint, you never call .enable() on a Task object :wink:

And please try to answer all questions :slight_smile:

septillion:
Small hint, you never call .enable() on a Task object :wink:

Just following the documentation of TaskScheduler in this case. They have the .enable() and .disable() calls for a reason: to have them used.

But anyway, we're totally digressing from what is primarily a C++ question. My original question, by the way, has been solved thanks to the good folk over at StackOverflow: I had to add the static keyword to the called function. Not completely there but it's a big step forward:

c++ - no known conversion for argument 3 from 'void (MyClass::*)()' to 'void (*)()' when instantiating in constructor - Stack Overflow=

When I get it working I'll start worrying about unnecessary objects. Last time I managed to compile it there was plenty of memory left.

wvmarle:
Just following the documentation of TaskScheduler in this case. They have the .enable() and .disable() calls for a reason: to have them used.

I know. But in the code you showed YOU don't do it :wink:

wvmarle:
But anyway, we're totally digressing from what is primarily a C++ question. My original question, by the way, has been solved thanks to the good folk over at StackOverflow:

I disagree, but you don't want to give answers. But if you like the people at StackOverflow better, fine. Then I wish you a good day sir! Saves me from wasting time.

I could dump my complete, original sketch here - but it's total a couple thousand lines by now, and spread out over more than a dozen files, which I don't think anyone is interested in wading through - it's also against the "how to use this forum" rules which ask for a minimal example demonstrating the problem, and that's what you got.

Besides, due to my perfectly non-exisitant version control I don't have a properly compiling version on my hands. For those two reasons it does not make sense to post those code bases.

Agreed I ignored some questions because they're quite irrelevant to the actual question at hand:

One, you are creating a lot of new objects of scheduler. Did you mean to create references?

I mean to get it working.

And why is the Scheduler created in the sketch?

Because I need to run a bunch of tasks, each at different intervals, and that's exactly what a Scheduler is doing for me. So I create a scheduler. Which is outside the scope of my question.

I tried to keep it simple - save you from wasting your time.

I'm not asking for all the code, I'm asking for this example to be complete / compilable / not have weird stuff in it.

wvmarle:
I mean to get it working.

That's what a mad code monkey says, not a programmer. :wink: A programmer thinks about what he tries to do.

wvmarle:
Because I need to run a bunch of tasks, each at different intervals, and that's exactly what a Scheduler is doing for me. So I create a scheduler. Which is outside the scope of my question.

Alright, fair enough. But (and this is just me not knowing the lib back to front) can't you have multiple Scheduler's? Although, alright, a single external might be easier.

septillion:
That's what a mad code monkey says, not a programmer. :wink: A programmer thinks about what he tries to do.
Alright, fair enough. But (and this is just me not knowing the lib back to front) can't you have multiple Scheduler's? Although, alright, a single external might be easier.

All part of the learning process. That's how I learn programming languages: by just doing it. Started programming C++ barely a few months ago, and still can barely get my head around pointers and references and so.

It should be possible to have multiple schedulers, but no idea how they interact. What's more, this set of libraries is supposed to become modular. That's why I broke a perfectly working setup. Each sensor it's own class, another that arranges all the settings, one more for the networking, and a Master that rules them all.

In the end the .ino shouldn't contain anything but the hardware parameters and a few calls to enable the sensors that are present, before handing off all control to the Master and the TaskScheduler.

I'm now in the first phase: make it work. Don't care too much for how. After that comes the second phase, which is make it fast (and when I hope to understand more of objects and can optimise a bit). Finally the third phase, make it pretty.

No problem in learning by doing. But that's no excuse to ignore advice :wink:

wvmarle:
I'm now in the first phase: make it work.

That's a terrible phase one. A better phase one would be to think it through :wink:

And it's not about making it fast. It's about not making a mess with weird side effects you have to fix later on.

I’m not familiar with these libraries but I would try like this:

initialize just a pointer in your class like this:

#ifndef HYDROMONITORMASTER_H
#define HYDROMONITORMASTER_H

#include <TaskScheduler.h>


class HydroMonitorMaster 
{
  public:
    HydroMonitorMaster();
    void begin(Scheduler);
  
  private:
  
    // The task scheduler.
    Scheduler ts;
    Task* tReadSensors; // here <<<<<<<<<<
    static void readSensors(void);

};
#endif

and then, use the new keyword to create the object…

#include <HydroMonitorMaster.h>
#include <TaskScheduler.h>


HydroMonitorMaster::HydroMonitorMaster() {
}

void HydroMonitorMaster::begin(Scheduler t) {

  // f is the task scheduler object, we use this to set up all the repeating tasks.
  ts = t;
  tReadSensors = new Task(10*1000, TASK_FOREVER, &readSensors, &ts, false);  // like this <<<<<<<<
  tReadSensors->enable();  // and then use the dereference operator here and anywhere else your want to access tReadSensors <<<<<<<<<<<<
}

void HydroMonitorMaster::readSensors() {
  // Go and read the sensors.
  
}

not tested, not compiled but you can try that.

septillion:
No problem in learning by doing. But that’s no excuse to ignore advice :wink:
That’s a terrible phase one. A better phase one would be to think it through :wink:

The thinking through is part of the process, which is why I’m now so much into modularising it. Can’t think it through before I have at least something going for it, then find out what’s good and what’s bad and fix it and get new ideas and implement it and go from there.

Looking at other people’s sketches I’ve gone a lot further already in software design than most do, but that’s because I’m thinking of the future. Multiple similar versions of the product (so can share the components as needed), long term maintenance, commercialisation and at the same time open sourcing both software and hardware.

It’s definitely not the first software project I take on (for another business of mine I built a web site with calendar and tour booking system plus management back end), the first though in C (or is it really C++? That’s also not all too clear to me), and the first that is running on embedded hardware.

To come back to the problem at hand. I contacted the author of TaskScheduler and he told me it’s not meant to be incorporated in other libraries, so probably that bit is going back to the main sketch. So be it. Just hope the tasks can be controlled from inside the library functions.

To get this to compile, a major step has been the initialisation of the tasks, like this:

#include <HydroMonitorMaster.h>

HydroMonitorMaster::HydroMonitorMaster() : 
    tReadSensors(10*1000, TASK_FOREVER,  &HydroMonitorMaster::readSensors, &ts, false),   
    tWiFiConnection(500, TASK_FOREVER, &HydroMonitorMaster::WiFiConnection, &ts, false),
    tWiFiBlink(500, TASK_FOREVER, &HydroMonitorMaster::WiFiBlink, &ts, false),         // Blinks the WiFi LED when in configuration mode.
    tSendData(10*60*1000, TASK_FOREVER, &HydroMonitorMaster::sendData, &ts, false)    // Sends the sensor data   to the cloud server.

{
// more stuff
}

That way I get this part to compile, but running into multiple other errors down the line. Not going to do anything, it’s deep in the night so that’ll have to wait for tomorrow or so. As said, probably going to move the task initialisation back to the setup() function, hope to have the library to be able to manage the existing tasks: enable(), disable(), and set callbacks.

wvmarle:
That way I get this part to compile, but running into multiple other errors down the line. Not going to do anything, it's deep in the night so that'll have to wait for tomorrow or so. As said, probably going to move the task initialisation back to the setup() function, hope to have the library to be able to manage the existing tasks: enable(), disable(), and set callbacks.

did you try the pointer method?

I would actually not incorporate any of the TaskScheduler’s functionality into another class/library.
TaskScheduler is designed to be a single static orchestrator of activities in a sketch, and therefore shoul exist outside of the libraries and classes.

Please check this example: GitHub - arkhipenko/IoT_apis2: IoT Enabled Automated Plant Irrigation System

The is a lot going on: WiFi, humidity measurement, LED blinking, etc. And scheduler is on top of it all.