【问题标题】:Static constant class member declaration静态常量类成员声明
【发布时间】:2012-09-19 06:34:34
【问题描述】:

在 Foo.h 中:

class Foo
{
public:
    Foo();
    static const unsigned int FOOBAR = 10;
    static const unsigned int BARFOO = 20;

private:
    unsigned int m_FooBar;
    bool m_Bar;
    void Bar();
};

在 Foo.cpp 中:

Foo::Foo()
    : m_FooBar(FOOBAR), // this works
      m_Bar(false)
{
}

void Foo::Bar()
{
    //m_FooBar = m_Bar ? FOOBAR : BARFOO; // linker fails *1
    m_FooBar = FOOBAR; // ok
}

我正在使用 GCC 4.5.3 进行编译。取消注释 *1 行时,链接器是否会失败?

Foo.o: In function 'Foo::Bar' (name unmangled):
Foo.cpp: undefined reference to `Foo::FOOBAR'
Foo.cpp: undefined reference to `Foo::BARFOO'

已尝试使用 VC2005、2008、2010 和 CB2010。他们都编译和链接得很好。为什么 GCC 在这种情况下会失败?

鉴于answer here,为什么其他流行的编译器没有像 GCC 一样失败?无论是对于 GCC 还是其他流行的编译器,它都必须是一个错误。还是有更合理的解释?

【问题讨论】:

  • 嗯...在VS2010中编译得很好。
  • @Mysticial 问题是关于 gcc 的。我可以确认链接器错误。
  • 已经提交as a bug
  • @ZachSaw:从技术上讲,你是对的。根据 ISO C++11 标准,这不是一个错误,因为直到 2012 年 2 月标准被批准后,对标准的更改才被投票纳入工作文件。但是,由于委员会确定这是当前标准中的缺陷,因此将其作为错误提交,以确保任何未来版本的 gcc 都表现出所需的行为(并且因为未来的标准将进行这些更正)。

标签: c++ gcc linker


【解决方案1】:

在形式上,头文件只声明了静态常量,它们也必须被定义(至少在 C++03 中)。但是,如果您只使用它们的值,您通常会侥幸逃脱。

在 C++11 中,这被更正式地指定为当静态是“odr-used”时需要定义。 *1 行就是一个例子。三元运算符试图形成对值的引用,而编译器(或实际上是链接器)意识到它不能。


C++11 标准说

9.4.2 静态数据成员
§3...
该成员仍应定义 如果在程序中使用了 odr-used (3.2) 并且命名空间范围定义不应在命名空间范围内 包含一个初始化器

【讨论】:

  • 但在 c++03 中,如果在标题中声明和定义整数静态常量就可以了,就像在问题中一样
  • 只要使用它们的值就可以了。三元运算符产生对两个值之一的引用,当它们未定义时,这是不可能的。如果您尝试通过引用函数来传递其中一个值,则会获得类似的效果。
  • 那么为什么其他流行的编译器不这样做呢?如果三元算子这样做,在VC2010上不应该也失败吗?
  • @Zach - 并非所有编译器都严格遵守标准。 :-) 一些早期的 VC 版本甚至声称不允许定义!
  • @BoPersson:是的。 VC6 根本不允许这样做!
【解决方案2】:

尝试定义这些成员:

static const unsigned int FOOBAR = 10;
static const unsigned int BARFOO = 20;

在类声明之外。

Foo::FOOBAR = 10;
Foo::BARFOO = 20;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 2015-12-15
    • 2011-02-24
    • 1970-01-01
    相关资源
    最近更新 更多