Inspired by the idea of "C++ HTML template engine that uses compile time HTML parsing", I am trying to write a sample class to check whether the first char in a string is a
.
int dummy[0];
class Test
{
public:
constexpr Test(const char *p):p_(p){}
constexpr void check()const
{
if (p_[0]!='a')
dummy[1]=0;
}
const char *p_;
};
constexpr Test operator"" _test(const char *pszText, size_t)
{
Test t(pszText);
t.check();
return t;
}
int main()
{
//dummy[1] = 0;
constexpr Test t = "baa"_test;
}
It works well(GCC7.1 on Ubuntu). If the first char is not a
, it will give a compile error:
main.cpp:29:24: error: array subscript value ‘1’ is outside the bounds
of array ‘dummy’ of type ‘int [0]’
constexpr Test t = "baa"_test;
What confused me is that if I change the code to:
int main()
{
dummy[1] = 0; //no compile error anymore
}
I am wondering when C++ reports an array out of bounds error.
constexpr
requires that the compiler evaluates the code. And, because, in the context of the C++ abstract machine, dummy[1]
is undefined behavior, it must emit a diagnostic. (This can be either a warning or an error. However, both g++
and clang++
choose to make this an error.)
However, just because dummy[1]
is undefined behavior in the context of the C++ abstract machine, doesn't mean that something else isn't defining the behavior. This means that the code should not necessarily be rejected (if the compiler itself doesn't need to use it). It simply is undefined behavior, not an error.
For instance, compiler writers will use out of bounds array accesses, and because they're writing the compiler, they can ensure that the behavior that occurs is the one desired. A good example is array memory management, where the pointer returned is typically one word past the beginning of the allocated memory (because the size also needs to be allocated.) So when the compiler writer needs to read the size he or she may do ((size_t const*)ptr)[-1]
.
That being said, a better way to trigger a compiler error in this case is to simply use a static assert: static_assert(p_[0]!='a', "String does not begin with 'a'.")
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With