使用const static非整数数据初始化的编译器行为,namespace vs struct

时间:2016-02-28 01:13:08

标签: static compilation initialization g++ const

假设我有两个不同版本的相同标题foo.hpp,第一个:

// File foo.hpp
#ifndef FILE_FOO
#define FILE_FOO
namespace X
{
  static const int    i = 13;
  static const double d = 17.0;
}
#endif

和第二个:

// File foo.hpp
#ifndef FILE_FOO
#define FILE_FOO
struct X
{
  static const int    i = 13;
  static const double d = 17.0;
};
#endif

在后一种情况下,使用结构毫无意义,但我是故意这样做的,以突出我的问题。在这两种情况下,我都尝试构建以下源文件foo.cpp

// File foo.cpp
#include "foo.hpp"
#include <iostream>
int main()
{
  std::cout << X::i << std::endl;
  std::cout << X::d << std::endl;
  return 0;
}

但仅在后者中我收到以下错误:

In file included from foo.cpp:2:
foo.hpp:7: error: floating-point literal cannot appear in a constant-expression
foo.hpp:7: error: ISO C++ forbids initialization of member constant ‘d’ of non-integral type ‘const double’

我正在使用g++ 4.2.1(仍然使用C ++ 98标准)和-pedantic,严格要求此选项以获得上述错误。

正如here所讨论的,我可以看到只允许在类内部初始化静态常量积分或枚举类型,因为我猜C ++标准没有指定在编译时应该如何实现浮点数它将它留给处理器。但在这一点上,命名空间案例误导了我......

最后,问题

  • 在上述两种情况下,编译器如何表现并将源转换为目标代码?
  • 为什么只在第二个版本的标题中出现错误?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

此外,我认为这个名称空间滥用的小例子可以帮助我们解释你的第一个问题(至少对于命名空间案例):

StaticNamespace.hpp:

#pragma once
namespace StaticNamespace
{
    static double d = 1.0;
}

Class.hpp:

#include "StaticNamespace.hpp"
#include <iostream>

class Class
{

public:

#if 1

    Class();

    void printFromSource() const;

#else

    Class(){
        StaticNamespace::d = StaticNamespace::d + 0.1;
    }

#endif

    void printFromHeader() const { std::cout<<"Class from header "<<StaticNamespace::d<<" "<<&StaticNamespace::d<<std::endl; }

    static void printDouble() { std::cout<<"Class static "<<StaticNamespace::d<<" "<<&StaticNamespace::d<<std::endl; }

};

Class.cpp:

#include "Class.hpp"

Class::Class()
{
    StaticNamespace::d = StaticNamespace::d + 0.1;
}

void Class::printFromSource() const
{
    std::cout<<"Class from source "<<StaticNamespace::d<<" "<<&StaticNamespace::d<<std::endl;
}

main.cpp中:

#include <iostream>
#include "Class.hpp"

int main ()
{
    Class test_class;

    test_class.printFromHeader();

#if 1
    test_class.printFromSource();
#endif

    Class::printDouble();
}

如果将预处理器ifs设置为true,则将有2个翻译单元,否则只有一个。正如您所看到的,两种情况下代码的不同行为与此示例中的每个转换单元都拥有静态变量的独立副本这一事实兼容。这当然只是一个微不足道的例子......