为什么用成员数组调用constexpr函数而不是常量表达式?

Jam*_*mes 28 c++ templates constexpr

我有以下帮助函数:

template<typename T, std::size_t N>
constexpr std::size_t Length(const T(&)[N]) {
    return N;
}
Run Code Online (Sandbox Code Playgroud)

返回静态数组的长度.在过去,这总是有效,但当我这样做时:

struct Foo
{
    unsigned int temp1[3];
    void Bar()
    {
        constexpr std::size_t t = Length(temp1); // Error here
    }
};
Run Code Online (Sandbox Code Playgroud)

使用MSVS 2017时出错:

error C2131: expression did not evaluate to a constant

note: failure was caused by a read of a variable outside its lifetime

note: see usage of 'this'
Run Code Online (Sandbox Code Playgroud)

我希望有人能说清楚我做错了什么.

Rak*_*111 20

MSVC是正确的.Length(temp1)不是一个恒定的表达.来自[expr.const] p2

表达式e是核心常量表达式,除非根据抽象机器的规则评估e将评估以下表达式之一:

  • this,除了constexpr函数或constexpr构造函数,作为e的一部分进行评估;

temp1this隐式评估(因为你指的是this->temp1),所以你没有一个常量表达式.gcc和clang接受它,因为它们支持VLA作为扩展(尝试使用-Werror=vla或编译-pedantic-errors).

为什么不允许这样做?好吧,您可以访问底层元素并可能修改它们.如果您正在处理constexpr正在计算为常量表达式的数组或数组,那么这是完全正常的,但如果不是,那么您不可能有一个常量表达式,因为您将操作在运行时设置的值.

  • @AnT虽然我完全同意禁用扩展通常是要走的路,但我们*特别*在这里谈论VLA,所以我想我只是提到了警告选项(`-Wvla`).此外,有时,摆脱代码库中的扩展必须一次发生一个扩展才是实用的. (5认同)
  • 如果你想用GCC来测试代码的标准有效性,那么用窄目标`-Werror = vla`悄悄地围绕它的众多扩展将没有多大意义.在这种情况下,标志的正确组合是`-std = ...`和`-pedantic-errors`. (4认同)