Kai-Uwe Bux said:
Alan Johnson wrote:
Kai-Uwe Bux said:
Denis Remezov wrote:
Kai-Uwe Bux wrote:
Note that, to my great dismay,
class X {
public:
static
const std::string str ( "abcd" ); // in one go? no!
}; // X
does *not* work. Actually, I do not know the reason.
I happened to come across 9.4.2/4 lately. It implies that only const
integral or const enumeration types can be initialised within a class
definition.
Denis
Thanks a lot,
that settles it then.
Do you have a guess as what the rational for the provisions of 9.4.2/4
might be? Admittedly, I have not the faintest idea.
Best
Kai-Uwe
Allowing integral/enum types to be initialized this way allows you to do
some convenient things. For example, consider the following:
class A
{
static const unsigned N ;
int i[N] ; // error.
public :
} ;
const unsigned A::N = 30 ;
But with this allowance, you could do this, instead:
class A
{
static const unsigned N = 30 ;
int i[N] ; // not an error.
public :
} ;
const unsigned A::N ; // Note that this is still needed if you plan on
using N elsewhere.
Further, creeating a constant integral value doesn't necessarily require
that the program *do* anything. That is, The initialization above
probably doesn't produce any executable code. You can't say the same
about, for example, a std::string, where initialization requires a call
to the constructor.
Alan
Thanks for the explanation,
I am reading the provision of the standard not as an allowance, though,
but as an restriction. I dislike the need to initialize non-integer/enum
constants far away from their definition. Do you know how the fact
that a constructor might get called relates to where in my source I put
the initialization?
Thanks again
Kai-Uwe
It may help understanding if we pretend to be a compiler (or rather, it
will help me to try to explain it. Please don't get the impression that
I am attempting to insult your ability to understand). As as compiler,
I rarely see a full picture of what is going on. Instead I just see
what is going on within the translation unit I am currently compiling.
So, let's say I'm compiling and encounter the following :
class C
{
static const std::string test("test") ;
} ;
Assuming this were allowed, and did the obvious thing, I only really
have one sensible choice about what to do. I reserve space for the
std::string option (in whatever manner I go about doing things like
that), and generate a call to std::string's constructor, and place it in
whatever place I normally put code that initializes static objects.
Now, let's say that was in a header file, as class declarations often
are. It is quite likely that I'll encounter that same thing again,
reserve more space for it, and generate another call to the constructor,
because how am I to know that that has already been done? But now I've
already violated the definition of a static class member, which is that
there is only one of them. Not to mention, the linker won't know what
to do with multiple symbols called C::test, and will probably spit out a
"multiply defined" error, or something similar.
Why do integral types not have the same problem? For integral types, the
compiler could just treat every subsequent place in which that
constant's value is needed as a literal with that value, much like a
#define (or it could do something much fancier. I really have no clue
what any actual implementations do).
So what is the "proper" place to put initializations of static members?
My opinion on this is that they should go in the same place as the
definitions for the member functions. That is, if you declare "class C"
in C.h, and implement it in C.cpp, then initialization of static members
should go in C.cpp (probably at the very top).
Alan