我想创建一个通用环缓冲类,用于获取不同类型的连接(uart
,can
等)。问题在于不同的命令类型/样式等。所以我决定只使用指针(我的意思是数字,而不是c指针)在环缓冲区中工作,并从它调用属于不同连接类型的函数。
所以我创建了这个类和typedef
函数指针:
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();
};
,这里是其中的put/read命令
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;
}
和(我在Visual Studio中测试逻辑,所以我使用一些只在桌面上有意义的命令)我创建了一个测试UART
类:
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);
};
和它的命令是:
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;
}
我想创建它的实例,比如
UART uart;
rbuf uartRB(BUFSIZE, uart.uartRBput, uart.uartRBget);
uart = UART(rbuf.putCommand);
作为一个想法,似乎很好,但我不知道如何实现它。这可能吗?这可能吗?
有办法解决这个问题。正如@Someprogrammerdude在评论中指出的那样,您可以使用std::function
、std::bind
和lambdas。
注意bufCommandProcessor
和putcmd
是普通的函数指针,不能与成员函数指针一起工作。
解决方案是std::function
和一些类型擦除器开销。例如,通过lambdas函数或std::bind_front
(自c++20起)包装要调用的实例及其成员函数,可以这样做:
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 }
{}
// ...
};
在UART
类
// 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 }
{}
// ...
};
现在在调用方
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) };
(参见示例)