I think my C++ is too rusty for this (never really got the hang of templates ).
So Iām calling for help on the most amazing community, although this is a pure C++ question and not a Particle one (although it is in connection with a library port for Particle).
Iāve got one controler class NexDisplay
that should house a map
of components derived off NexObject
base class.
So I originally went this way (.h & .cpp seperated of course ;-))
TL;DR: The most puzzling error messages I canāt wrap my head round are at the bottom of this post
class NexDisplay
{
public:
...
NexObject& add(uint8_t pageID, uint8_t compID, const char* name, void *value = NULL, bool withEvents = false, bool global = false)
{
uint16_t key = (pageID << 8) || compID;
std::pair<std::map<uint16_t, NexObject>::iterator, bool> ret;
ret = __components.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(pageID, compID, name, value));
return ret.first->second;
}
NexObject& add(NexPage& page, uint8_t compID, const char* name, void *value = NULL, bool withEvents = false, bool global = false)
{
uint16_t key = (page.__pid << 8) || compID;
std::pair<std::map<uint16_t, NexObject>::iterator, bool> ret;
ret = __components.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(*this, page, compID, name, value));
return ret.first->second;
}
...
protected:
std::map<uint16_t, NexObject> __components; /* map to hold all components for standard access */
...
friend class NexPage; // grant access to protected functions / fields for NexPage
};
class NexObject
{
public:
NexObject(NexDisplay& display, NexPage& page, uint8_t cid, const char *name, void *value = NULL)
{
this->__display = &display;
this->__page = &page;
this->__pid = page.__pid;
this->__cid = cid;
this->__name = name;
this->__value = value;
}
...
protected: /* data */
NexDisplay* __display; /* pointer to the owning display for hardware access */
NexPage* __page; /* pointer to the owning page (NexPages are selfowned) */
uint8_t __pid = 0; /* Page ID (will be set even for global compnents) */
uint8_t __cid = 0; /* Component ID */
const char *__name; /* An unique name */
void *__value;
friend class NexDisplay; // grant access to protected functions / fields for NexDisplay
};
class NexTouch: public NexObject
{
public
NexTouch(NexDisplay& display, NexPage& page, uint8_t cid, const char *name, void *value = NULL)
: NexObject(display, page, cid, name, value) { }
...
};
class NexPage: public NexTouch
{
public:
NexPage(NexDisplay& display, uint8_t pid, const char *name, void *value = NULL)
: NexTouch(display, *this, 0, name, value) { this->__pid = pid; }
...
};
NexObject& NexPage::add(uint8_t compID, const char* name, void* value, bool withEvents, bool global)
{
return __display->add(*this, compID, name, value, withEvents, global);
}
class NexText : public NexTouch { ... };
class NexButton: public NexTouch { ... };
...
And having set things up like this, Iād use it like that
NexDisplay display; // the display is the root element
NexPage &pgMain = display.add(0, 0, "pg0");
NexText &nxText = (NexText &)pgMain.add(1, "txt0");
NexButton &nxBtn0 = (NexButton &)pgMain.add(2, "btn0");
NexButton &nxBtn1 = (NexButton &)pgMain.add(3, "btn1");
But I didnāt like all the casting and thought, why not give templates
a try, but I just seem to not get it to work.
I tried to alter the above like this (no worries, not as long again)
template<class T> T& NexDisplay::add(uint8_t pageID, uint8_t compID, const char* name, void* value, bool withEvents, bool global)
{
uint16_t key = (pageID << 8) || compID;
std::pair<std::map<uint16_t, NexObject>::iterator, bool> ret;
ret = __components.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(pageID, compID, name, value));
return (T)ret.first->second;
}
template<class T> T& NexDisplay::add(NexPage& page, uint8_t compID, const char* name, void* value, bool withEvents, bool global)
{
uint16_t key = (page.__pid << 8) || compID;
std::pair<std::map<uint16_t, NexObject>::iterator, bool> ret;
ret = __components.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(*this, page, compID, name, value));
return (T)ret.first->second;
}
template<class T> T& NexPage::add(uint8_t compID, const char* name, void* value, bool withEvents, bool global)
{
return __display->add<T>(*this, compID, name, value, withEvents, global);
}
// usage
NexDisplay display; // the display is the root element
NexPage &pgMain = display.add(0, 0, "pg0");
NexText &nxText = pgMain.add(1, "txt0");
NexButton &nxBtn0 = pgMain.add(2, "btn0");
NexButton &nxBtn1 = pgMain.add(3, "btn1");
But I just canāt get this to build - Iāve tried all sorts of things, but obviously not the right one.
This one e.g. gave that error
Timer.cpp:88:50: error: no matching function for call to 'NexDisplay::add(int, int, const char [4])'
NexPage &pgMain = display.add(0, 0, "pg0");
In file included from ITEADLIB_Nextion.h:18:0,
from Timer.cpp:28:
NexDisplay.h:99:24:
note: template<class T> T& NexDisplay::add(uint8_t, uint8_t, const char*, void*, bool, bool)
template<class T> T& add(uint8_t pageID, uint8_t compID, const char* name, void *value = NULL, bool withEvents = false, bool global = false);
NexDisplay.h:99:24: note:
template argument deduction/substitution failed:
Timer.cpp:88:50: note:
couldn't deduce template parameter 'T'
NexPage &pgMain = display.add(0, 0, "pg0");
Timer.cpp:89:47: error: no matching function for call to 'NexPage::add(int, const char [5])'
NexText &nxText = pgMain.add(1, "txt0");
So I changed it this way (which somehow counteracts the purpose of getting rid of the need to provide the type)
NexDisplay display; // the display is the root element
NexPage &pgMain = display.add<NexPage >(0, 0, "pg0");
NexText &nxText = pgMain.add<NexText >(1, "txt0");
NexButton &nxBtn0 = pgMain.add<NexButton>(2, "btn0");
NexButton &nxBtn1 = pgMain.add<NexButton>(3, "btn1");
OK, got this solved, by putting the implementation of the templated functions into the headers - duh
But I now have a āunsolvableā situation where Iām chasing my own tail.
Having the implementation inside the header renders forward declaration of the needed classes impossible but #includ
ing the needed class causes a
In file included from NexPage.h:26:0,
from Nextion.h:41,
from ITEADLIB_Nextion.h:17,
from ITEADLIB_Nextion.cpp:17:
NexDisplay.h: In member function 'T& NexDisplay::add(NexPage&, uint8_t, const char*, void*, bool, bool)':
NexDisplay.h:117:25: error: invalid use of incomplete type 'class NexPage'
uint16_t key = (page.__pid << 8) || compID;
^
In file included from Nextion.h:33:0,
from ITEADLIB_Nextion.h:17,
from ITEADLIB_Nextion.cpp:17:
NexObject.h:31:7: error: forward declaration of 'class NexPage'
class NexPage; // forward declare required class
^
Iāll put a complete - not building - branch dumbplate
on GitHub, if anybody wants to be so kind and have a go at this.
As final goal (if possible) Iād still like it to have the version without the need to provide the type <Nex....>
working.
Any help will be appreciated