在 C++ 中传递内联临时 class 需要是常量。如何解决这个问题
Passing inline temporary class in c++ needs to be const. How to work around this
我想用 c++11 为不同的 CPU(实际上是 MCU)编写可移植代码。由于某些 CPU 不支持直接通过其内存地址 space 读取程序数据(例如 Atmel AVR),我需要一个使用直接地址或自定义地址调用函数的解决方案使 Stream 指针通过一些外部存储读取数据。
将此代码视为自定义库:
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
现在,我想实现一个函数,它使用内存地址或 Stream 从以下位置读取数据:
// 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
接下来,我想用一个 Stream 调用 PrintMessage,但是这个流需要内联创建,在 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.
}
上面的所有代码都可以编译并运行,但我主要担心的是我需要在 PrintMessage 函数中使用 const 参数(否则我会收到错误消息)。因此,我需要做一个丑陋的造型:
Send( ((IStream*)&stream)->ReadChar() );
这基本上使参数成为非常量以避免错误。但是有没有更好的解决方案来“合法”地做到这一点?
流实例本身不能是 const,因为它在内部提升了它的位置,但 C++ 要求将它作为 const 传递,因为它是一个始终被视为右值的内联临时变量。
我认为修改自身的临时变量没有任何危害,在 PrintMessage 函数之后 return 它无论如何都会被丢弃。
内联require最后想做的是这个:
#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"));
}
知道如何在不强制转换以丢弃错误的情况下正确执行此操作吗?或者上面的当前代码是否可以接受?
使用 C++11,您可以简单地将右值引用作为参数。
void PrintMessage(IStream && stream)
右值引用将绑定到临时对象,并且在这种情况下与左值引用几乎没有区别。
要么是你的界面不对,要么是你的用法不对。目前您正在 const_cast
直播。如果你传递了一个 const
IStream 对象,那将是未定义的行为。
或者:
class IStream
{
public: virtual char ReadChar() const;
};
或者:
void PrintMessage(IStream& stream)
{
while (true) // TODO: end condition
Send(stream.ReadChar());
}
void PrintMessage(IStream&& stream)
{
while (true) // TODO: end condition
Send(stream.ReadChar());
}
int main(void)
{
PrintMessage(ConstMemoryStream("Hello!"));
}
我想用 c++11 为不同的 CPU(实际上是 MCU)编写可移植代码。由于某些 CPU 不支持直接通过其内存地址 space 读取程序数据(例如 Atmel AVR),我需要一个使用直接地址或自定义地址调用函数的解决方案使 Stream 指针通过一些外部存储读取数据。
将此代码视为自定义库:
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
现在,我想实现一个函数,它使用内存地址或 Stream 从以下位置读取数据:
// 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
接下来,我想用一个 Stream 调用 PrintMessage,但是这个流需要内联创建,在 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.
}
上面的所有代码都可以编译并运行,但我主要担心的是我需要在 PrintMessage 函数中使用 const 参数(否则我会收到错误消息)。因此,我需要做一个丑陋的造型:
Send( ((IStream*)&stream)->ReadChar() );
这基本上使参数成为非常量以避免错误。但是有没有更好的解决方案来“合法”地做到这一点?
流实例本身不能是 const,因为它在内部提升了它的位置,但 C++ 要求将它作为 const 传递,因为它是一个始终被视为右值的内联临时变量。
我认为修改自身的临时变量没有任何危害,在 PrintMessage 函数之后 return 它无论如何都会被丢弃。
内联require最后想做的是这个:
#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"));
}
知道如何在不强制转换以丢弃错误的情况下正确执行此操作吗?或者上面的当前代码是否可以接受?
使用 C++11,您可以简单地将右值引用作为参数。
void PrintMessage(IStream && stream)
右值引用将绑定到临时对象,并且在这种情况下与左值引用几乎没有区别。
要么是你的界面不对,要么是你的用法不对。目前您正在 const_cast
直播。如果你传递了一个 const
IStream 对象,那将是未定义的行为。
或者:
class IStream
{
public: virtual char ReadChar() const;
};
或者:
void PrintMessage(IStream& stream)
{
while (true) // TODO: end condition
Send(stream.ReadChar());
}
void PrintMessage(IStream&& stream)
{
while (true) // TODO: end condition
Send(stream.ReadChar());
}
int main(void)
{
PrintMessage(ConstMemoryStream("Hello!"));
}