helmet_23
helmet_23

Reputation: 405

Compiler behavior with const static non integral data initialization, namespace vs struct

Let say that I have two different versions of the same header foo.hpp, the first one:

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

and the second one:

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

In the latter case the use of a structure is pointless, but I have done it on purpose to highlight my question. In both cases I have tried to build the following source file 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;
}

but only in the latter I get the following error:

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’

I am using g++ 4.2.1 (so still with C++98 standard) and -pedantic, this option is strictly required to get the above error.

As discussed here, I can see the point of allowing only static constant integral or enumeration types to be initialized inside the class, because I guess the C++ standard does not specify how floating point should be implemented at compile time and it leaves it to the processor. But at this point the namespace case is misleading me...

Finally, the questions:

Thanks for your help!

Upvotes: 1

Views: 109

Answers (2)

Christopher23
Christopher23

Reputation: 126

Moreover, I think that this small example of namespace misuse could help us to shed some light on your first question (at least for the namespace case):

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();
}

If you set the preprocessor ifs to true you will have 2 translation units, otherwise there will be just one. As you can see the different behavior of the code in the two cases is compatible to the fact that each translation unit in this example owns an independent copy of the static variable. This is just a trivial example of course...

Upvotes: 1

Christopher23
Christopher23

Reputation: 126

I think you could find some useful information (maybe not a complete answer to your question..) in the following discussion: Why can't I have a non-integral static const member in a class?

Upvotes: 1

Related Questions