我认为我对C ++编译时表达式非常了解(著名的遗言)。我看到Microsoft Visual C ++中带有 constexpr 表达式的行为使我感到惊讶,并且我确定这是一个(相当重要的IMO)错误。
g ++的行为方式与我的期望/理解相符,这为我的解释提供了支持。但是我不是专业人士,所以我想确保它不在某种“未定义行为”灰色区域。
首先,我的总体理解是 constexpr 表达式(以及其他特征/限制):
如果上述正确,则MSVC确实存在一个错误,因为可以在以下示例中修改 constexpr 类实例的 可变 成员。 constexpr 表达式-副作用。在此修改的“之后”与“之前”评估时,其值将有所不同。 (这里的“之前”和“之后”不是在运行时执行方面,而是在 constexpr 表达式的编译时评估中……其顺序甚至可能没有明确定义? )
这里完全煮熟了:
struct Foo
{
mutable int m_i {1};
};
constexpr Foo f;
template <int I> // Template so *compile-time* value of constexpr
void Bar() {std::cout << I << std::endl;} // expressions can be examined
int main(int argc, char** argv)
{
Bar<f.m_i>(); // MSVC prints "1". g++ issues an error on this line to the
// effect of "mutable member data usable in a constexpr
// expression". I believe g++ shows the correct behavior.
Bar<(f.m_i = 2)>(); // MSVC prints "2". The constexpr expression "f.m_i = 2" causes a
// side-effect (global value f.m_i is modified)
Bar<f.m_i>(); // MSVC prints "2". So the same constexpr "f.m_i" evaluates to
// different values depending on what has been compiled so far.
}
在MSVC上,尽管 f.m_i 的值根据已编译到目前为止的内容而变化,但是(当然)不受运行时的影响条件和执行顺序:
int main(int argc, char** argv)
{
Bar<f.m_i>();
if (argc >= 2)
{
Bar<(f.m_i = 2)>();
}
Bar<f.m_i>(); // (MSVC prints "2" regardless of runtime argc value)
}