'Class and interclass member function pointers
I want to create a universal ring buffer class for taking different types of connections (uart
, can
, etc). The problem is in different command types/styles/etc in them. So I decided to work only with pointers (I mean number, not c-pointer) in ring buffer and call functions belonging to different connection types from it.
So I've created this class and typedef
for function pointer:
typedef bool(*bufCommandProcessor)(uint8_t pointer);
class rbuf
{
uint8_t bufsize;
uint8_t psize;
uint8_t readPointer;
uint8_t writePointer;
bufCommandProcessor processPut;
bufCommandProcessor processRead;
public:
rbuf();
rbuf(uint8_t bsize, bufCommandProcessor putpr, bufCommandProcessor readpr);
uint8_t cyclicPlus(uint8_t num, uint8_t maxval);
bool checkEmpty();
bool checkFull();
bool putCommand();
bool readCommand();
};
and here are put/read commands from it
bool rbuf::putCommand()
{
if (checkFull())
{
readPointer = cyclicPlus(readPointer, psize);
this->processPut(writePointer % bufsize);
writePointer = cyclicPlus(writePointer, psize);
}
else {
this->processPut(writePointer % bufsize);
writePointer = cyclicPlus(writePointer, psize);
}
return true;
}
bool rbuf::readCommand()
{
if (checkEmpty()) {
return false;
}
this->processRead(readPointer % bufsize);
readPointer = cyclicPlus(readPointer, psize);
return true;
}
and also (I'm testing logic in Visual Studio, so I use some command that have sense only on desktops) I've created a test UART
class:
typedef bool(*putcmd)();
class UART
{
uint8_t RingBuffer[BUFSIZE][STRINGSIZE] {};
uint8_t Command[STRINGSIZE];
uint8_t Len;
putcmd uput;
UART();
UART(putcmd cput);
void cmdcm(uint8_t* cmd, uint8_t len);
bool uartRBput(uint8_t wp);
bool uartRBget(uint8_t rp);
};
and its commands are:
UART::UART(putcmd cput)
{
Command[0] = 0;
Len = 0;
RingBuffer[0][0] = 0;
uput = cput;
}
void UART::cmdcm(uint8_t* cmd, uint8_t len)
{
Len = len;
memcpy(Command, cmd, Len);
memset(&Command[Len], 0, STRINGSIZE-Len);
uput();
}
bool UART::uartRBput(uint8_t wp)
{
memcpy(RingBuffer[wp], Command, STRINGSIZE);
return true;
}
And I want to create instances of it like
UART uart;
rbuf uartRB(BUFSIZE, uart.uartRBput, uart.uartRBget);
uart = UART(rbuf.putCommand);
As an idea, it seems nice, but I cannot figure out how to realize it. Is it even possible?
Solution 1:[1]
Is it even possible?
There are ways to work this out. As @Someprogrammerdude pointed in the comments, you could use std::function
, std::bind
, and lambdas.
Note that the bufCommandProcessor
and putcmd
are normal function pointers which will not work with the member function pointers.
The solution is std::function
with some type-eraser overhead.
For instance, wrapping the instace to call and its member function via a lambdas function or std::bind_front
(since c++20) you can do as follows:
Iin rbuf
class:
// type aliases for callable function object
using bufCommandProcessor = std::function<bool(uint8_t)>;
class rbuf
{
// ....
bufCommandProcessor processPut;
bufCommandProcessor processRead;
public:
rbuf() {}
rbuf(uint8_t bsize, bufCommandProcessor putpr, bufCommandProcessor readpr)
: processPut{ putpr }
, processRead{ readpr }
{}
// ...
};
In UART
class
// type aliases for callable function object
using putcmd = std::function<bool()>;
class UART
{
// ...
std::function<bool()> uput;
public:
UART() = default;
UART(putcmd cput)
: uput{ cput }
{}
// ...
};
Now in caller side
UART uart;
rbuf uartRB{ 10u
, [uart](uint8_t wp) mutable { return uart.uartRBput(wp); }
, [uart](uint8_t rp) mutable { return uart.uartRBget(rp); }
};
// alternatively using std::bind_front
uart = UART{ std::bind_front(&rbuf::putCommand, uartRB) };
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |