此代码是否已损坏或是否存在g ++中的错误?

mat*_*267 21 c++ linker-errors

由于一些奇怪的原因,g ++(版本4.5.0和4.5.2)无法编译此代码:

bool somefunc() {
    return false;
}

class C {
  public:
    static const int a = 0;
    static const int b = 1;
};

class myclass {
  public:
    int check() {
        return somefunc() ? C::a : C::b;
        // if(somefunc()) return C::a; else return C::b;
    }
};

int main() {
    myclass obj;
    obj.check();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它给了我这个错误:

/tmp/ccyvvTUy.o:/home/mati/test.cpp:14: undefined reference to `C::a'
/tmp/ccyvvTUy.o:/home/mati/test.cpp:14: undefined reference to `C::b'
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

如果我将有问题的行更改为注释行,它编译得很好,这很奇怪.我的代码是否有问题以及我对C++不了解的东西或它只是G ++中的一个错误?

Kon*_*lph 18

关于此代码是否实际合法,目前仍存在争议.

无论哪种方式,根据一些读数常量实际上也需要在使用前进行定义,不只是声明.那是,

class C {
  public:
    static const int a = 0;
    static const int b = 1;
};

const int C::a;
const int C::b;
Run Code Online (Sandbox Code Playgroud)

或者只是使用enum用于容纳旧编译器的hack(但这可能毕竟是唯一的合法方式):

class C {
  public:
    enum { a = 0, b = 1 };
};
Run Code Online (Sandbox Code Playgroud)

  • @ matix2267这并不容易.如果标准不需要对此代码进行诊断,那么对于不同的优化设置,行为实际上可能在法律上有所不同.此外,请注意这是*链接时间*,而不是编译时间,错误,编译器将跳过整个函数,因为您不在任何地方使用结果(并且它是在编译时已知的常量). (4认同)
  • @ matix2267,错误来自链接器,而不是编译器.优化器简单地优化了使链接器跳闸的输出. (4认同)
  • 尽管GCC应该拒绝或接受这个代码,无论是否有优化,它应该接受或拒绝这个版本,并且取消注释另一行,所以这是某种错误. (2认同)

Mar*_*k B 5

见9.4.2/4:

如果静态数据成员是const integral或const枚举类型,则它在类定义中的声明可以指定一个常量初始值设定项,它应该是一个整型常量表达式(5.19).在这种情况下,成员可以在其范围内出现在整数常量表达式中.如果在程序中使用该成员,并且名称空间范围定义不包含初始化程序,则该成员仍应在名称空间作用域中定义.

关于"使用"的确切含义存在一些争论(我相信),尽管我的理解大致是if程序需要变量的地址然后在此上下文中"使用".在我看来,将三元组改为if/else或改变优化级别可能会改变程序视图(如g ++所见)从而导致失败或成功,这似乎并不合理.另请注意,如果您违反此要求,则不会对所需的诊断进行任何说明.

始终定义静态成员不会出错.