constexpr表达式有副作用吗? (在MSVC上)

时间:2018-11-16 19:55:12

标签: c++

我认为我对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)
}

0 个答案:

没有答案