受到" C++ HTML template engine that uses compile time HTML parsing"的启发,我试图编写一个示例类来检查字符串中的第一个字符是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;
}
效果很好(Ubuntu上的GCC7.1)。如果第一个char不是a
,则会产生编译错误:
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;
让我感到困惑的是,如果我将代码更改为:
int main()
{
dummy[1] = 0; //no compile error anymore
}
我想知道C ++何时报告数组越界错误。
答案 0 :(得分:3)
constexpr
要求编译器评估代码。并且,因为在C ++抽象机器的上下文中,dummy[1]
是未定义的行为,它必须发出诊断。 (这可能是警告或错误。但是,g++
和clang++
都选择将此错误。)
然而,仅仅因为dummy[1]
在C ++抽象机器的上下文中是未定义的行为,并不意味着其他东西不能定义行为。这意味着不一定要拒绝代码(如果编译器本身不需要使用它)。它只是未定义的行为,而不是错误。
例如,编译器编写器将使用越界数组访问,并且因为他们正在编写编译器,所以他们可以确保发生的行为是所需的行为。一个很好的例子是数组内存管理,其中返回的指针通常是一个字超过分配的内存的开头(因为大小也需要分配。)所以当编译器编写者需要读取他或她可能做的大小时{ {1}}。
话虽这么说,在这种情况下触发编译器错误的更好方法是简单地使用静态断言:((size_t const*)ptr)[-1]
。