Я хочу написать переносимый код на C ++ 11 для разных процессоров (на самом деле MCU). Поскольку некоторые ЦП не поддерживают чтение данных программы напрямую через адресное пространство памяти (например, Atmel AVR), мне нужно решение, которое вызывает функцию либо с прямым адресом, либо с указателем потока, созданным на заказ, для чтения данных через некоторые внешние место хранения.
Рассмотрим этот код как пользовательскую библиотеку:
class IStream
{
public: virtual char ReadChar();
};
class ConstMemoryStream : public IStream
{
const char* Position;
public: ConstMemoryStream(const char* startAddress)
{
Position = startAddress;
}
public: char ReadChar() override
{
return *Position++;
}
};
void Send(char data) { } // Send data to serial port
Теперь я хочу реализовать функцию, которая принимает либо адрес памяти, либо поток для чтения данных из:
// const parameter is needed here, otherwise error: invalid initialisation of non-const reference of type 'IStream&' from an rvalue of type 'IStream'
void PrintMessage(const IStream& stream)
{
while (true) // TODO: end condition
//Send(stream.ReadChar()); // this gives an error because i need to use a const parameter: passing 'const IStream' as 'this' argument discards qualifiers
Send( ((IStream*)&stream)->ReadChar() ); // this works, this actually bypass the error above. IS THIS OK?????
}
void PrintMessage(char* address); // overload to use memory instead of stream. implementation not important here
Затем я хочу вызвать PrintMessage с помощью Stream, но этот поток должен быть создан встроенным и больше не нужен вне функции PrintMessage:
int main(void)
{
// Requirement: ConstMemoryStream needs to be created and passed INLINE PrintMessage
PrintMessage(ConstMemoryStream("Hello!")); // This works only if i put const in PrintMessage parameter.
}
Весь приведенный выше код компилируется и работает, но меня больше всего беспокоит то, что мне нужно использовать параметр const в функции PrintMessage (иначе я получаю сообщение об ошибке). Из-за этого мне нужно сделать уродливое приведение:
Send( ((IStream*)&stream)->ReadChar() );
Это в основном делает параметр неконстантным, чтобы избежать ошибки. Но есть ли лучшее решение сделать это на законных основаниях?
Сам экземпляр потока не может быть константным, потому что он увеличивает его положение внутри, но С ++ требует передать его как константу, потому что это встроенная временная переменная, которая всегда рассматривается как rvalue.
Я не вижу никакого вреда в том, что временная переменная изменяет сама себя, после того, как функция PrintMessage вернет ее, она все равно отбрасывается.
В конце концов я хочу сделать следующее:
#ifdef CPU_AVR
#define CSTR(str) ConstMemoryStream(PROGMEM str) // the PROGMEM attribute puts the text in a separate space not accessible in regular memory
#elif defined CPU_SAM
#define CSTR(str) (char*)str
#endif
int main2(void)
{
// If the CPU does not support direct address mapping to it's FLASH space, pass a stream instead of a direct memory pointer
PrintMessage(CSTR("Hello"));
}
Есть идеи, как это сделать правильно, не отбрасывая ошибку? Или текущий код, приведенный выше, приемлем?