GVKun编程网logo

Switch Java问题:case表达式必须是常量表达式(switch语句中case后只能为常量)

93

针对SwitchJava问题:case表达式必须是常量表达式和switch语句中case后只能为常量这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展android–Switch–case表达

针对Switch Java问题:case表达式必须是常量表达式switch语句中case后只能为常量这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展android – Switch – case表达式必须是常量表达式、c – 分配内存rvalue表达式或lvalue表达式的表达式?、c – 在constexpr中使用argc,是否严格要求所涉及的任何子表达式都是常量表达式?、c – 考虑到非常数表达式函数的内建是gcc是常量表达式等相关知识,希望可以帮助到你。

本文目录一览:

Switch Java问题:case表达式必须是常量表达式(switch语句中case后只能为常量)

Switch Java问题:case表达式必须是常量表达式(switch语句中case后只能为常量)

我在switch / case语句中遇到问题。该错误显示:“
case表达式必须是常量表达式”。我理解该错误,可以使用If来解决它,但是有人可以告诉我为什么case表达式在switch /
case中必须是常量。我的错误的代码示例:

public boolean onOptionsItemSelected(MenuItem item) {    int idDirectory = ((MenuItem) findViewById(R.id.createDirectory)).getItemId();    int idSuppression = ((MenuItem) findViewById(R.id.recycleTrash)).getItemId();    int idSeeTrash = ((MenuItem) findViewById(R.id.seeTrash)).getItemId();    switch (item.getItemId()) {    case idDirectory:        createDirectory(currentDirectory);        break;    case idSuppression:        recycleTrash();        break;    case idSeeTrash:        seeTrash();        break;    }    return super.onOptionsItemSelected(item);}

谢谢你的解释!!

答案1

小编典典

因此可以在编译阶段进行评估(静态检查)

请参阅:http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11为的正式定义switch

此外,它可以帮助您更好地了解如何将switch其转换为字节码:

class Switch {  void x(int n ) {    switch( n ) {      case 1: System.out.println("one"); break;      case 9: System.out.println("nine"); break;      default:  System.out.println("nothing"); break;    }  }}

并在编译后:

C:\>javap -c SwitchCompiled from "Switch.java"class Switch extends java.lang.Object{Switch();  Code:   0:   aload_0   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V   4:   returnvoid x(int);  Code:   0:   iload_1   1:   lookupswitch{ //2                1: 28;                9: 39;                default: 50 }   28:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;   31:  ldc     #3; //String one   33:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V   36:  goto    58   39:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;   42:  ldc     #5; //String nine   44:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V   47:  goto    58   50:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;   53:  ldc     #6; //String nothing   55:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V   58:  return}

看到标记为 1:

 1:   lookupswitch{ //2            1: 28;            9: 39;            default: 50 }

它评估该值并转到其他行。例如,如果值为value 9,它将跳转到指令39:

   39:  getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;   42:  ldc     #5; //String nine   44:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V   47:  goto    58

依次跳转到指令58:

   58:  return

如果它是动态评估的,那么所有这些都是不可能的。这就是为什么。

android – Switch – case表达式必须是常量表达式

android – Switch – case表达式必须是常量表达式

我正在使用ActionBarSherlock,然后使用onoptionsItemSelected在单击特定菜单项时启动新活动.代码在添加ABS之前正常工作,现在我得到case表达式必须是常量表达式错误的情况.

@Override
    public boolean onoptionsItemSelected(com.actionbarsherlock.view.MenuItem item) 
    {
        switch (item.getItemId()) {
        case R.id.about: //error
            startActivity(new Intent(this, AboutActivity.class));
            break;
        case R.id.Feedback: //error
            //launch activity
            break;

        default:
            break;
        return super.onoptionsItemSelected(item);
    }

在添加ActionBarSherlock之前,相同的代码工作正常.

解决方法:

我用if / else替换了switch / case语句.您可以单击开关,然后按下CTRL 1(如果您在Eclipse中).

c – 分配内存rvalue表达式或lvalue表达式的表达式?

c – 分配内存rvalue表达式或lvalue表达式的表达式?

让我说下面的代码
int main(){    new int; // Is this expression l-value or r-value??    return 0;}

我知道lvalues是持久性对象(因为它在内存中具有特定的位置,即使在表达式结束之后我们也可以访问它),并且rvalue是临时对象(在表达式结束之后,它没有位置在内存中蒸发).

我看到一些这是rvalue表达的地方.如果表达式返回一个地址(内存中的特定位置),那么怎么能是rvalue呢?或者是否值得重新计算,因为表达式new int返回(地址值),它会在表达式结束后消失,永远不会被捕获.

解决方法

new int是一个r值.

你不能使用:

int i;(new int) = &i;

也许你正在考虑由new int返回地址的对象.
表示返回地址的对象的表达式*(new int)是一个l值.您可以使用:

*(new int) = 10;

这不是很好的代码.它泄漏内存,但它是合法的代码.

c – 在constexpr中使用argc,是否严格要求所涉及的任何子表达式都是常量表达式?

c – 在constexpr中使用argc,是否严格要求所涉及的任何子表达式都是常量表达式?

例:
int main(int argc,char**)
{
    constexpr int a = argc * 0;
    (void)a;
    constexpr int b = argc - argc;
    (void)b;
    return 0;
}

argc不是常量表达式,但在两种情况下,编译器仍然能够在编译时(即0)计算a和b的结果.

g++接受上面的代码,而clang和MSVC14拒绝它.

标准是否允许编译器在constexpr方面与g一样聪明?

解决方法

argc * 0和argc – argc都不是常量表达式,在某些情况下允许左值到右值的转换,这些都不适用于此处.如果我们查看草案C 11标准第5.19节[expr.const],它会列出例外情况.它说:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially
evaluated subexpression […]

并且有几个子弹,包括以下关于左值到右值的转换:

an lvalue-to-rvalue conversion (4.1) unless it is applied to

  • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding
    initialization,initialized with a constant expression,or

  • a glvalue of literal type that refers to a non-volatile object defined with constexpr,or that refers
    to a sub-object of such an object,or

  • a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not
    ended,initialized with a constant expression;

有趣的是,gcc不接受以下代码(see it live):

constexpr int a = argc * 2;

所以看起来gcc说我知道结果将为零,因此它执行常量折叠,并且不需要执行argc的左值到右值转换来确定结果.

不幸的是,我认为第5.19节中没有任何条款允许这种短路.这看起来非常类似于int a=1,is a || 1 a constant expression?中的情况,其中有一个错误报告,但gcc团队中没有人回复那个.我在该错误报告中添加了一个comment,表明这似乎是相关的.

马克的评论如下表明这是一个错误:

There is a whole c++-delayed-folding branch on which some gcc developers are working,which will delay a number of optimizations and might fix this. It is important for other reasons,rejecting the code in this question is very low priority

常量表达式是否严格要求每个子表达式都是常量表达式?不,例如5.19它说:(强调我的)

A conditional-expression is a core constant expression unless it involves one of the following as a potentially
evaluated subexpression (3.2),but subexpressions of logical AND (5.14),logical OR (5.15),and conditional
(5.16) operations that are not evaluated are not considered
[…]

所以以下是一个常量表达式:

constexpr int a = false && argc * 0;

因为argc * 0未评估,因为&&评估从左到右和短路.

c – 考虑到非常数表达式函数的内建是gcc是常量表达式

c – 考虑到非常数表达式函数的内建是gcc是常量表达式

请参阅更新以获得更好的问题样本.原始代码混合了一些混乱的问题:

这个问题Why can I call a non-constexpr function inside a constexpr function?提出了以下代码

#include <stdio.h>constexpr int f(){    return printf("a side effect!\n");}int main(){    char a[f()];    printf("%zd\n",sizeof a);}

我正在回答的是不正确的,但是gcc 4.8.2允许它(see it live).

但是,如果我们使用-fno-builtin标志,gcc会生成错误(see it live):

error: call to non-constexpr function 'int printf(const char*,...)'     return printf("a side effect!\n");                                     ^

所以看来gcc正在考虑它的内置版本的printf作为一个常数表达式. gcc documents builtins here但是没有记录这种情况,其中一个非constexpr函数的内置函数可以被认为是一个常量表达式.

如果确实如此:

编译器是否允许这样做?
>如果允许的话,他们是否必须将其记录为符合标准?
>这可以被认为是扩展,如果是这样,似乎这将需要警告,因为C++ draft standard第1.4节实施合规第8段说(强调我的):

A conforming implementation may have extensions (including additional library functions),provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so,however,they can compile and execute such programs.

更新

正如凯西指出的那样,在原始问题中有一些事情使它成为一个很差的例子.一个简单的例子是使用std::pow这不是一个constexpr函数:

#include <cmath>#include <cstdio>constexpr double f(){    return std::pow( 2.0,2.0 ) ;}int main(){    constexpr double x = f() ;    printf( "%f\n",x ) ;}

编译和编译没有任何警告或错误(see it live),但添加-fno-builtin使其生成错误(see it live).注意:why math functions are not constexpr in C++11:

error: call to non-constexpr function 'double pow(double,double)'     return std::pow( 2.0,2.0 ) ;                               ^

解决方法

是的,gcc正在考虑将一些 builtin functions作为constexpr,即使标准没有明确标记它们.我们可以在gcc bug报告 [C++0x] sinh vs asinh vs constexpr中找到与cmath中发现的数学函数有关的讨论:

LWG 2013 does seem to allow GCC to treat these functions as constexpr.
So,fixed for 4.7

这是指LWG issue 2013,其原始建议的决议是将以下内容添加到第17.6.5.6节[constexpr.functions](重点是我的未来):

[…]Additionally,an implementation may declare any function to be
constexpr if that function’s deFinition satisfies the necessary
constraints[…]

但在C11之后,该决议被撤销,最终决议最终如下:

[…]An implementation shall not declare any standard library function
signature as constexpr except for those where it is explicitly
required.[..]

所以这是目前(在C 14)a explicitly non-conforming extension,据我所知,这是不符合C11,因为它改变了可观察的行为,因此不允许通过as-if规则.

Jonathan Wakely指出了一个libstdc邮件列表讨论:PR libstdc++/49813 revisited: constexpr on functions (and builtins)由于上述问题,上面讨论了重新打开上面提到的错误报告:

I believe we should re-open the bug in light of the actual resolution
of LWG 2013 (adding constexpr is forbidden).

The FE should not treat builtins as constexpr in strict-conformance
mode.

We should either remove _GLIBCXX_CONSTEXPR from <cmath> entirely or make it conditional on __STRICT_ANSI__.

今天关于Switch Java问题:case表达式必须是常量表达式switch语句中case后只能为常量的讲解已经结束,谢谢您的阅读,如果想了解更多关于android – Switch – case表达式必须是常量表达式、c – 分配内存rvalue表达式或lvalue表达式的表达式?、c – 在constexpr中使用argc,是否严格要求所涉及的任何子表达式都是常量表达式?、c – 考虑到非常数表达式函数的内建是gcc是常量表达式的相关知识,请在本站搜索。

本文标签: