3

使用 C++03:

在 foo.h 中:

class Foo {
    public:
        // Declare integral static constant with an initializer
        static const int some_constant = 42;
};

在 foo.cc 中:

// Define and reserve storage for Foo::some_constant
const int Foo::some_constant;

在 bar.cc 中:

#include <foo.h>
// stuff that uses Foo::some_constant;

长期以来,我一直认为以上是正确的方法。如果类范围的 static 是整数类型并且初始化程序是常量表达式,则允许它具有初始化程序。同样,您必须始终在一个翻译单元中声明静态存储(mod 模板,但让我们忽略它)。

但是,MSVC 2010、2012 和显然 2013 RC 都无法链接同时包含 foo.cc 和 bar.cc 的程序,声称 Foo::some_constant 是多重定义的。

我是否误解了某些事情并做错了,还是 VC 在这里出错了?如果是后者,是否有人参考了错误报告或类似内容?

请不要告诉我将初始化程序移动到 .cpp 文件中。我知道我可以做到这一点,但现在我从语言规则和编译器实现质量的角度对此更感兴趣,而不是变通方法。

4

4 回答 4

2

你是对的; 您编写它的方式是正确的,而 VS 是错误的。

但是,VS 可能会出错,因为您没有禁用编译器扩展。如果您使用/Za标志编译,那么它应该可以正常工作。

或者,您可以将定义包装在预处理器#if块中:

#if !_MSC_EXTENSIONS
// Define and reserve storage for Foo::some_constant
const int Foo::some_constant;
#endif
于 2013-09-12T20:56:35.880 回答
1

如果您使用初始化程序来初始化静态 const 成员,则不需要在类之外进行声明。例如:

namespace std
{
    template<typename T , T val>
    struct integral_constant
    {
        typedef T value_type;
        static const T value = val;
    };
}
于 2013-09-12T18:18:14.810 回答
1

MSVC 基于 C++ 标准不正确。当包含在其他 CPP 中时,头文件中的静态成员some_constant不是定义。所以不应该有多个符号定义。以下是 C++ 标准的引用(重点是我的)。

声明是一个定义,除非它声明一个函数而不指定函数体(8.4),它包含外部说明符(7.1.1)或链接说明25(7.5),既不是初始化程序也不是函数体,它声明了一个类定义中的静态数据成员(9.2, 9.4),它是一个类名声明 (9.1),它是一个 opaque-enum-declaration (7.2),它是一个模板参数 (14.1),它是一个参数-函数声明器中的声明 (8.3.5) 不是函数定义的声明器,或者它是 typedef 声明 (7.1.3)、别名声明 (7.1.3)、使用声明 (7.3. 3)、静态断言声明(第 7 条)、属性声明(第 7 条)、空声明(第 7 条)或使用指令(7.3.4)。

于 2013-09-13T11:25:50.107 回答
0

将初始化从声明移到定义,即从 foo.h 移到 foo.cc。

foo.cc:

// Define and reserve storage for Foo::some_constant
const int Foo::some_constant = 42;

如果 foo.cc 和 bar.cc#include "foo.h"编译器看到初始化两次并抱怨多个定义。foo.h 应该读

class Foo {
public:
    // Declare integral static constant here, initialize outside
    static const int some_constant;
};
于 2013-09-12T20:49:30.650 回答