11

我似乎遗漏了一些相当基本的东西。我试图在编译时使用 const 数组成员。

const int list[3] = { 2, 5, 7 };
const int a = list[2]; // this doesn't error?

template<int N1, int N2>
struct tmax {
  enum { value = ((N1 > N2) ? N1 : N2) };
};

const int b = tmax<2,4>::value;
const int c = tmax<list[0],list[1]>::value; // error is here

int main()
{
  return 0;
}

错误:

prog.cpp:10:24: error: 'list' cannot appear in a constant-expression
prog.cpp:10:30: error: an array reference cannot appear in a constant-expression

这是相关的 IDEOne 链接

那么为什么这不起作用呢?我错过了什么?我应该怎么做?

4

2 回答 2

9

仅仅因为一个对象const并不意味着它是一个编译时常量表达式。

main.cpp:10:20: error: non-type template argument is not a constant expression
const int c = tmax<list[0],list[1]>::value; // error is here
                   ^~~~~~~
main.cpp:10:20: note: read of non-constexpr variable 'list' is not allowed in a constant expression
main.cpp:1:11: note: declared here
const int list[3] = { 2, 5, 7 };
          ^

这是原因constexpr

constexpr int list[3] = { 2, 5, 7 };

template<int N1, int N2>
struct tmax {
    enum { value = ((N1 > N2) ? N1 : N2) };
};

const int b = tmax<2,4>::value;
const int c = tmax<list[0],list[1]>::value; // works fine now

至于为什么会这样:

const int a = list[2]; // this doesn't error?

初始化const变量不需要常量表达式:

int foo(int n) {
    const int a = n; // initializing const var with a non-compile time constant
于 2012-06-09T23:18:04.493 回答
4

如果表达式包含许多不允许的子表达式中的任何一个,则表达式不是常量表达式。一类不允许的子表达式是:

  • 左值到右值的转换(4.1),除非它应用于
    • 一个整数或枚举类型的左值,它引用一个非易失 const 对象,该对象具有前面的初始化,用常量表达式初始化,或者
    • 一个字面量类型的左值,它指的是用 定义的非易失性对象constexpr,或者指的是这样一个对象的子对象,或者
    • 一个字面量类型的左值,它引用一个生命周期尚未结束的非易失性临时对象,用一个常量表达式初始化;

特别是,当使用常量初始化器初始化的枚举或整数类型的 const 对象的名称形成一个常量表达式(读取其值是导致左值到右值转换的原因)时,一个 const 聚合对象的子对象(例如如list在您的示例中,数组)不会,但如果声明constexpr.

const int list[3] = { 2, 5, 7 };
const int a = list[2];

这是有效的,但a不构成常量表达式,因为它不是用常量表达式初始化的。

通过更改 的声明list(我们不必更改 的声明a),我们可以使aform 成为一个常量表达式。

constexpr int list[3] = { 2, 5, 7 };
const int a = list[2];

由于list[2]现在是一个常量表达式a现在是一个用常量表达式const初始化的整数类型的对象,因此现在可以用作常量表达式。a

于 2012-06-09T23:35:50.527 回答