表达式不是常量

24

我在一个switch语句中遇到了'case expression not constant'的错误。但是,头文件为使用的常量提供了定义,在其初始化列表中构造函数为它们提供了初始化。

此外,当我鼠标悬停在“问题”语句上时,它将它们识别为常量。

const int ThisClass::EXAMPLE_CONSTANT

error expression must have a constant value

这对我来说似乎有点违反直觉。我进行了一些研究,并找到了一个类似的问题,其他人也遇到过。他们被告知所有常量实际上必须在“main”函数中初始化,并且这是语言的限制。这是真的吗?看起来不太可能。


1
请提供能够演示问题的实际代码。您粘贴的内容并没有什么帮助。 - tenfour
1
你使用的编译器是什么?它真的是C++吗? - harper
5个回答

21
case语句需要在编译时已知的整数值,这就是所谓的常量。但是const成员并不是以这种意义上的常量存在的。它们只是只读的。

你可以使用enum来代替字段:

class ThisClass
{
    public:

        enum Constants
        {
            EXAMPLE_CONSTANT = 10,
            ANOTHER_CONSTANT = 20
        };    
};

然后你就可以写:

switch(c)
{
      case ThisClass::EXAMPLE_CONSTANT:
                   //code
                   break;
      case ThisClass::ANOTHER_CONSTANT:
                   //code
                   break;
};

4
如果这些常量之间没有关联,我建议使用一个未命名的枚举。 - Sebastian Mach
这个 C++ 特性有点糟糕,在我的情况下,const int ThisClass::EXAMPLE_CONSTANT 是一个 API 代码,我不能更改它。 - Zhang
@张:如果你的常量实际上不是在编译时已知的常量,而是只读的,那么你不能像我上面展示的那样使用 switch()。但是,你可以使用一个以你的常量为键、以函数为值的映射表! - Nawaz

5
你需要一个“真正”的编译时整数常量。在C++中,const表示只读,而const变量可以像int y = 0; const int x = y;一样初始化,使得x成为了只读的值,其值是在初始化时的y的值。使用现代编译器,你可以使用enumconstexpr来存储(整数)编译时常量的成员:
class Foo {
public:
    static constexpr int x = 0;
    enum { y = 1 };
};

int main () {
    switch (0) {
    case Foo::x: ;
    case Foo::y: ;
    }
}

1
constexpr 不会使成员变量静态化。 - R. Martinho Fernandes

2
这里有一些混乱。在C++中,const可以用于多个方面,例如声明实际常量和只读变量。
如果您声明:
```cpp const int x = 5; ```
那么x就是一个真正的常量,不能更改。
另一方面,如果您声明:
```cpp const int *y = &x; ```
那么*y不是常量,但是它指向的值是一个常量,不能通过*y更改它。
const int x = 0;

在全局、命名空间或局部作用域中,它是一个常量。你可以在需要常量表达式的地方使用它(比如 case 标签或数组大小)。然而,在类作用域或函数参数中,它只是一个只读变量。
此外,如果你在类作用域中声明:
static const int x = 0;

这也是一个常量。

1
在函数作用域内声明为const int的变量,并使用整数常量表达式进行初始化,则其本身在C++中形成整数常量表达式。因此,在函数作用域中,它不仅是“只读变量”。 - AnT stands with Russia
@AndreyT 哎呀,我是说函数参数 :) 谢谢。 - R. Martinho Fernandes

1

std::map + C++11 lambdas解决方法

此方法允许非常量,应该给我们O(1)摊销在C++中使用HashMap的最佳方法是什么?:

#include <ctime>
#include <functional>
#include <unordered_map>
#include <iostream>

int main() {
    int result;
    int key0 = std::time(NULL) % 3;
    int key1 = (key0 + 1) % 3;
    int key2 = (key0 + 2) % 3;
    std::unordered_map<int,std::function<void()>> m{
        {key0, [&](){ result = 0; }},
        {key1, [&](){ result = 1; }},
        {key2, [&](){ result = 2; }},
    };
    m[key0]();
    std::cout << key0 << " " << result << std::endl;
    m[key1]();
    std::cout << key1 << " " << result << std::endl;
    m[key2]();
    std::cout << key2 << " " << result << std::endl;
}

可能的输出:
1 0
2 1
0 2

如果要在类内使用,请不要忘记像为什么Switch语句不能用于字符串?所示静态地构建映射表。


1

在 case 标签中使用的常量必须是 整数常量表达式。一个 整数常量表达式 必须满足比仅仅被声明为 const 的整数对象更严格的一组要求。

非静态类成员不能用于整数常量表达式,因此您正在尝试的操作将无法编译。例如,如果其初始化程序在使用点处“可见”,则可以在整数常量表达式中使用静态类成员。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接