I am reading a book on writing modern C++ code for microcontrollers which is named "Real time C++". I am trying to write the codes in the book myself. However, while copying the code from the book and trying to build it, I got a compilation error of:
error C2131: expression did not evaluate to a constant.
message : a non-constant (sub-) expression was encountered
I inserted the relevant part of the code below:
#include <cstdint>
#include <iomanip>
#include <iostream>
namespace mcal
{
namespace reg
{
// Simulate the transmit and receive hardware buffers on the PC.
std::uint8_t dummy_register_tbuf;
std::uint8_t dummy_register_rbuf;
}
}
class communication
{
private:
static constexpr std::uint8_t* tbuf = reinterpret_cast<std::uint8_t*>(&mcal::reg::dummy_register_tbuf);
static constexpr std::uint8_t* rbuf = reinterpret_cast<std::uint8_t*>(&mcal::reg::dummy_register_rbuf);
};
/* rest of the nonrelated code */
The error indicates those two lines where casting happens. I know that we try to use static constexpr integral class member variables, because this ensures optimization (constant folding) on them. I think that the error happens because we try to set a nonconstant variable to a constant variable, but I can be wrong surely. So, I would kindly ask you to explain to me what is the real problem here and why the author did such a mistake (if it is a mistake). Also, if you additionally point out the correct way of casting I would highly appreciate. Thank you very much.
>Solution :
It is unclear what the intention behind the reinterpret_cast is, but the program is ill-formed.
constexpr on a variable requires that the initializer is a constant expression. But an expression is disqualified from being a constant expression if it would evaluate a reinterpret_cast. Therefore the initialization is ill-formed.
However, nothing else in the initialization stops it from being a constant expression and so
static constexpr std::uint8_t* tbuf = &mcal::reg::dummy_register_tbuf;
will just work and the reinterpret_cast would be a redundant anyway since it would cast between identical pointer types which is specified to result in the same value.
GCC, ICC and MSVC up to v19.16 do seem to erroneously accept the code (https://godbolt.org/z/YKjhxqo3v). Maybe the author tested the code only on one of these compilers.
For GCC there is a bug report here.