【问题标题】:Why don't static member variables play well with the ternary operator?为什么静态成员变量不能很好地与三元运算符一起使用?
【发布时间】:2011-07-23 16:37:13
【问题描述】:

这是交易。我有一个静态类,其中包含几个用于获取输入的静态函数。该类包含一个私有静态成员变量,用于指示用户是否输入了任何信息。每种输入法都会检查用户是否输入了任何信息,并相应地设置状态变量。我认为这将是使用三元运算符的好时机。不幸的是,我不能,因为编译器不喜欢那样。

我复制了这个问题,然后尽可能地简化了我的代码以使其易于理解。这不是我的原始代码。

这是我的头文件:

#include <iostream>

using namespace std;

class Test {
public:
    void go ();
private:
    static const int GOOD = 0;
    static const int BAD = 1;
};

这是我使用三元运算符的实现:

#include "test.h"

void Test::go () {
    int num = 3;
    int localStatus;
    localStatus = (num > 2) ? GOOD : BAD;
}

这里是主要功能:

#include <iostream>
#include "test.h"

using namespace std;

int main () {
    Test test = Test();
    test.go();
    return 0;
}

当我尝试编译它时,我收到以下错误消息:

test.o: In function `Test::go()':
test.cpp:(.text+0x17): undefined reference to `Test::GOOD'
test.cpp:(.text+0x1f): undefined reference to `Test::BAD'
collect2: ld returned 1 exit status

但是,如果我替换这个:

localStatus = (num > 2) ? GOOD : BAD;

用这个:

if (num > 2) {
    localStatus = GOOD;
} else {
    localStatus = BAD;
}

代码按预期编译和运行。什么晦涩的 C++ 规则或 GCC 极端案例是造成这种疯狂的原因? (我在 Ubuntu 9.10 上使用 GCC 4.4.1。)

【问题讨论】:

    标签: c++ static ternary-operator static-members


    【解决方案1】:

    这是根据 C++ 标准。三元运算符确实构成了一个左值,它将在运行时引用GOODBAD。左值到右值的转换不会立即应用于左值GOODBAD,因此您需要定义GOODBAD

    查看核心语言问题报告http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#712

    作为一种解决方法,您可以对int 应用显式强制转换(读取它们的值,从而进行左值到右值的转换)或使用读取值的运算符,例如+

    localStatus = (num > 2) ? +GOOD : +BAD;
    

    【讨论】:

    • 标准在哪里区分这两种情况?他们不是都“使用”GOOD,因此需要定义吗?我认为只是 gcc 足够聪明,可以避免在 lvalue GOOD 被用作赋值的 RHS 的情况下使用外部链接(因此立即转换 lvaue-rvalue),但在这种情况下没有管理它的左值GOOD 用于三元运算符,但我准备相信我错了。
    • @Steve 如果你做+GOODint a = GOOD,你在左值GOOD 上进行左值到右值的转换(“直接” - 见3.2p2,它说在这种情况下你不要'不要“使用”变量)。如果您执行int a = x ? a : b;,您将对三元运算符产生的左值进行左值到右值的转换,而不是对ab 产生的左值进行。
    • 啊,你对詹姆斯的评论回答了我的问题。它们的特点是在 C++03 之后但在 2008 年提出该缺陷之前插入草稿中的文本。我认为当前的标准正如我所说的那样。我的打印副本和我的 2003(E) 的 PDF 都说:“如果对象或非重载函数的名称出现在可能求值的表达式中,则使用它。”没有例外。
    【解决方案2】:
    class Test {
        static const int GOOD = 0;
        static const int BAD = 1;
    };
    

    这些只是声明;它们不是定义。您需要在您的 .cpp 文件之一中提供类定义之外的静态成员变量的定义:

    const int Test::GOOD;
    const int Test::BAD;
    

    或者,对于整数常量,使用enum 通常更方便:

    class Test {
        enum { 
            GOOD = 0,
            BAD = 1 
        };
    };
    

    【讨论】:

    • 为什么缺少定义会困扰三元运算符而不是标准赋值运算符?
    • 没有那么简单。看我的回答。
    • @Evan:你说的是哪个赋值运算符?给 GOOD 和 BAD 赋值的那个?
    • @Evan:我不是 100% 确定,但我会尝试回答:当您使用直接赋值时,GOODBAD 仅直接用作右值。但是,当您使用条件运算符时,条件表达式num &gt; 2 ? GOOD : BAD 本身就是一个左值表达式,因此直到选择了GOODBAD 之后才会正式进行左值到右值的转换,因此实际对象(带有定义)是必需的。
    【解决方案3】:

    您的代码对我来说看起来不错。并且ideone 同意:见this link。但那是 gcc-4.3.4。但是,我的 gcc-4.4.0 不接受它。所以不管是什么原因,都不是很明显。

    编辑添加:以下变体在 gcc-4.4.0 下编译:

    int localStatus = 42 ? GOOD : BAD;
    

    提醒:以下代码无法编译:

    int localStatus = (num == 42) ? GOOD : BAD;
    

    所以有人在某个地方搞砸了。

    【讨论】:

    • 我不确定是否有人在某个地方搞砸了。我相信,在第一种情况下,唯一发生的事情是,表达式被优化了。但真正的问题仍然存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    相关资源
    最近更新 更多