【问题标题】:Expected constant expression fails miserably in switch statement预期的常量表达式在 switch 语句中惨遭失败
【发布时间】:2010-08-13 16:30:08
【问题描述】:

假设我有一个这样定义的类“代码”,用户指定的类型转换为 int:

class Code
{
public:    
    int code;
    std::string description;

    Code (const int c, const std::string& d) : code(c), description(d) { ; }

    operator int() const { return code; }
};

还有一个使用代码类的第二类“大师”:

class Master
{
public:
    Code master_code;
};

还有一堆预先指定的代码,像这样:

const Code CODE_ONE    (1, "This is code one");
const Code CODE_TWO    (2, "This is code two");
const Code CODE_THREE  (3, "This is code three");

人们会认为(即我会认为)可以这样使用它:

Master master_obj;
switch (master_obj.master_code)
{
    case CODE_ONE:
        // ...
        break;

    case CODE_TWO:
        // ...
        break;

    case CODE_THREE:
        // ...
        break;

    default:
        // ...
}

由于自动将类型转换为 int,但显然情况并非如此。 GCC 告诉我 CODE_ONE、CODE_TWO 和 CODE_THREE“不能出现在常量表达式中”。

顺便说一句,这也不起作用:

Master master_obj;
switch (master_obj.master_code)
{
    case CODE_ONE.code:
        // ...
        break;

    case CODE_TWO.code:
        // ...
        break;

    case CODE_THREE.code:
        // ...
        break;

    default:
        // ...
}

上面返回完全相同的错误:“'CODE_ONE' 不能出现在常量表达式中”除了一个“'。”不能出现在常量表达式中”。

但这确实有效:

Master master_obj;
switch (master_obj.master_code)
{
    case 1:
        // ...
        break;

    case 2:
        // ...
        break;

    case 3:
        // ...
        break;

    default:
        // ...
}

所以 CODE_ONE 等不能被解析为常量表达式?这似乎很奇怪......还是我做错了什么?

【问题讨论】:

    标签: c++ types expression switch-statement constants


    【解决方案1】:

    switch 语句中的标签必须是“整数常量表达式”(第 6.4.2/2 节)。整数常量表达式”定义为 (§5.19/1):

    整型常量表达式只能包含字面量 (2.13)、枚举器、常量变量或使用常量表达式初始化的整型或枚举类型的静态数据成员 (8.5)、整型或枚举类型的非类型模板参数,以及 sizeof表达式。浮动文字 (2.13.3) 只有在转换为整数或枚举类型时才能出现。只能使用到整数或枚举类型的类型转换。特别是,除了 sizeof 表达式,不得使用函数、类对象、指针或引用,不得使用赋值、递增、递减、函数调用或逗号运算符。

    因此,您不能进行函数调用(包括转换函数),并且数据成员必须是静态的(您的不是)。

    【讨论】:

    • @oystein:我应该补充一点,C++0x 确实扩展了常量表达式的概念。它添加了constexpr,您可以使用它来将事物标记为常量表达式,因此对于int constexpr f() { return 1; } 之类的东西,您可以使用f() 作为常量表达式。
    【解决方案2】:

    开关标签必须是编译时常量。在运行时创建 CODE_XXX 对象之前,您要比较的值不可用。

    【讨论】:

      【解决方案3】:

      switch case 语句的 case 标签应该是编译时常量并且应该是整数。 CODE_ONE、CODE_TWO 等不是编译时积分常数。

      参考 6.4.2/2

      【讨论】:

        【解决方案4】:

        CODE_ONE, ... 等被定义为 const 的事实并不意味着它们实际上是常量表达式。 const 所做的只是“尝试”并强制这些类实例不会被 const 定义的规则改变。最后,类(或结构体)实例永远不会被视为完全常量表达式,因为它是一个动态对象。

        switch 语句需要的是一个“编译时常量表达式”,就 C++98 的所有意图和目的而言,它是一个 int 字面量或枚举值(最后也是 int 字面量)。

        C++0x' constexpr 可以让你做更复杂的事情,比如使用常量函数,但不是你想要的。

        【讨论】:

          猜你喜欢
          • 2018-04-25
          • 1970-01-01
          • 2023-01-16
          • 2023-03-28
          • 2011-07-07
          • 1970-01-01
          • 2017-01-28
          • 1970-01-01
          • 2011-04-19
          相关资源
          最近更新 更多