Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Static const integral data members can be initialized?

Reply
Thread Tools

Static const integral data members can be initialized?

 
 
SG
Guest
Posts: n/a
 
      07-23-2010
On 22 Jul., 23:42, Immortal Nephi wrote:
> Why do Microsoft C++ Compiler reports:
>
> error C2864: 'obj::y' : only static const integral data members
> can be initialized within a class


Because the ISO C++ standard says so. But if you're looking for a
reason why it is the way it is, I think there is no good answer.

But you will be pleased to know that C++0x will extend this rule to
all "literal types" including floats and even user-defined literal
types (such as std::complex<double> for example).

Keep in mind that an in-class initializer for static const members is
not a substitute for a definition. So, if you try to take the address
of such an object or bind it to a reference you have to provide a
definition as well.

Cheers!
SG
 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      07-23-2010
On Jul 22, 11:06 pm, Ian Collins <(E-Mail Removed)> wrote:
> On 07/23/10 09:42 AM, Immortal Nephi wrote:


> > Why do Microsoft C++ Compiler reports:


> > error C2864: 'obj::y' : only static const integral data
> > members can be initialized within a class


> > float and double keywords are not allowed to be in static
> > const inside class.


> float and double are not integral types.


But they can still be declared as static const inside a class.

> Their representation my differ between the build host and the
> deployment environment.


That's true for integral types as well. The official
justification for not allowing them here is that an in range
floating point literal might represent a different value in the
two environments (which isn't true of integral types, which are
always exact); i.e. the exact value of something like:
double const pi = 3.14159;
will be different on a PC than on an IBM mainframe.

--
James Kanze
 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      07-23-2010
On Jul 23, 1:40 am, Ian Collins <(E-Mail Removed)> wrote:
> On 07/23/10 12:21 PM, TJorgenson wrote:
> > On Jul 22, 4:49 pm, Ian Collins<(E-Mail Removed)> wrote:


> >>>> I'm sure a resident language lawyer can quote the chapter
> >>>> and verse, but from a practical point of view, an
> >>>> initialisation within a class is a compile time constant.
> >>>> The compiler can substitute the literal value as an
> >>>> optimisation. Initialisations outside of the class are
> >>>> performed at run time before main is called.


> >>> So you are saying that the following class definition:


> >>> class D
> >>> {
> >>> static const double d;
> >>> };


> >>> with the following definition in a cpp file:


> >>> const double D::d = 0.1;


> >>> could cause the compiler to generate initialization code
> >>> for this constant that runs before main is called to
> >>> generate the constant in the format for the target
> >>> processor that may be different from the host that the
> >>> compiler runs on. Agreed.


> >>> But if the compiler can generate this initialization code,
> >>> I contend that it could also generate the constant in the
> >>> correct target format as well. After all, the compiler
> >>> needs to know the target processor instruction set to
> >>> generate the code. I still don't think this justifies why
> >>> floats and doubles can't be initialized within a class
> >>> definition.


> >> But where do you stop? If floating point values can be
> >> compile time constants, can they be used in switch cases?
> >> As template parameters?


> > I get your point, but I'm not arguing for that. Switch cases
> > with floats would essentially require automatic generation
> > of direct equality comparisons, which could be problematic.
> > I also understand that allowing template parameters to be
> > floats and doubles could cause the generated code to have
> > behavior that is processor/compiler/ compiler-option
> > dependent. This would be bad IMO.


> > I just think initialization of all static constants could be
> > allowed within a class.


> OK, consider how a compiler should evaluate


> static const double d = 42.42*3.5/6;


The same way it would if this were a variable at namespace
scope.

> > I also think that the standard should not require that
> > constants that are initialized within a class also be
> > defined outside the class, unless the code explicitly takes
> > the address of the constant somewhere. I would expect a link
> > error for that.


> The wording of 9.4.2/4 is:


The wording in the draft of C++0x has changed considerably. It
allows the initializer for all "literal types". All scalar
types are literal types, as are some class types, so you can
write things like:

class POD { int a; int b; };

class Toto
{
static double const d = 3.14159;
static POD const c = { 42, -1 };
// ...
};

(if I've understood correctly), and an expression like Toto::c.a
would be an integral constant expression.

> If a static data member is of const integral or const
> enumeration type, its declaration in the class definition can
> specify a constant initializer which shall be an integral
> constant expression (5.19). In that case, the member can
> appear in integral constant expressions within its scope. The
> member shall still be defined in a namespace scope if it is
> used in the program and the namespace scope definition shall
> not contain an initializer.


> "used in the program" is is rather woolly.


§3.2/2:
An expression is potentially evaluated unless is the
operand of the sizeof operator (5.3.3), or is the
operand of the typeid operator and does not designate
an lvalue of polymorphic class type (5.2.. An object
or non-overloaded function is used if its name appears
in a potentially-evaluated expression. [...]

The last "used" is in italics, so this is a definition of the
term. (The text goes on to define what used means for other
things, like virtual functions, etc.)

> > We have been getting away with not defining static const
> > integers outside the class in most cases even though it is
> > strictly illegal, but some constructs seem to generate code
> > that requires the out-of- class definition. For example,
> > with our latest compiler using static const integers in
> > a conditional operator (? seems to require the out-
> > of-class definition if the constants are any integer types
> > other that int and unsigned int. This is a PITA IMO and it
> > makes it hard for me to sell my colleges on the idea that it
> > is better to use static const integers rather than #define.


> If your colleagues (I assume you made a typo!) want to use
> #define, you are in the wrong job!


Or rather his colleagues are in the wrong job.

--
James Kanze
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      07-23-2010
On Jul 23, 2:14 am, TJorgenson <(E-Mail Removed)> wrote:
> On Jul 22, 5:40 pm, Ian Collins <(E-Mail Removed)> wrote:


[...]
> > "used in the program" is is rather woolly.


> I still think the standard could restrict "if it is used in
> the program" to be "if its address is taken in the program".
> What other "use in the program" (sic) should require
> a definition at namespace scope?


Creating a reference to it?

Formally, a variable (const or not) is an lvalue. Anytime the
lvalue is not immediately converted to an rvalue, you would need
the definition. In theory, at least.

Note that if you have something like:

struct Toto { static int const a = 42; };

and somewhere write:

std::vector<int> v;
v.push_back(Toto::a);

you need the definition, since vector:ush_back uses pass by
reference. (In practice, vector:ush_back is probably inlined,
and if the compiler actually inlines it, then it might not
really need the reference.)

> I think it is rare to take the address of a static constant integer


Perhaps not that rare, if you remember that pass by reference
counts as "taking the address", and that a lot of templated
functions regularly use pass by reference, even when the
template is instantiated on an int.

> and if you do so without providing the out-of-class definition
> you will get a linker error that will be immediately fixed.


Typically, for something like v.push_back, you'll only get the
linker error if the compiler doesn't inline the code for some
reason.

> The standard language makes it the compiler writer’s job to
> decide when the out-of-class definition is required,


No. The standard language says that if the out-of-class
definition is absent, it is undefined behavior. Which means
that it's up to the user to get it right; the compiler writer
doesn't have to do anything.

> meaning that code may work now, but some day somebody adds
> code that requires that definition and then we get the linker
> error and have to explain why the definition wasn't necessary
> before (even though it technically was).


Technically, the definition was necessary; the compiler just
didn't detect the error. What you're proposing has the opposite
effect: the definition might not be necessary now, but some
change in the use of the class would make it necessary.

The simplest rule is to always provide the definition,
regardless of what the standard or the compiler require.

--
James Kanze
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      07-23-2010
On Jul 23, 1:30 pm, Pete Becker <(E-Mail Removed)> wrote:
> On 2010-07-22 18:17:00 -0400, TJorgenson said:
> > On Jul 22, 3:06 pm, Ian Collins <(E-Mail Removed)> wrote:
> >> On 07/23/10 09:42 AM, Immortal Nephi wrote:


> >> float and double are not integral types.


> >> Their representation my differ between the build host and the deployment
> >> environment.


> > And how exactly does initialization outside the class definition help
> > in this regard?


> > It seems to me that allowing initialization of static const float and
> > double within a class would not break anything and would be a useful
> > construct. I believe the problem you mention would be the same either
> > way.


> The difference is that floating-point values are not
> constant-expressions (in the terminology of the language definition).


You mean integral constant expressions, I think.
A floating-point literal is a constant expression (at least for
the purpose of non-local static object initialization).

> That means that they can't be used in places where a
> constant-expression is required, such as the size of an array:


> const int size = 1;
> int arr[size]; // OK
> const double dsize = 1.0;
> int darr[(int)dsize]; // error: dsize not a constant-expression


Interestingly enough,
int darr[(int)3.14159];
is legal.

> Initialization within a class definition was originally
> designed to support constant-expressions, not as a general
> initialization technique.


Yes. Originally, IIRC, allowing the initialization expression
in the class definition was considered a hack, necessary to
support things like:
struct Toto
{
static int const size = 10;
char array[size];
};
, but not something one would really want to use if one could
avoid it.

--
James Kanze
 
Reply With Quote
 
Bo Persson
Guest
Posts: n/a
 
      07-23-2010
TJorgenson wrote:
> On Jul 22, 5:40 pm, Ian Collins <(E-Mail Removed)> wrote:
>>
>> OK, consider how a compiler should evaluate
>>
>> static const double d = 42.42*3.5/6;
>>

> Ideally, the compiler should evaluate double constants the same way
> the target environment will evaluate doubles, but this is still not
> relevant to _where_ this constant expression lives (i.e. in the
> class or outside).
>


Constants yes, but not expressions. If you require multiplication and
division, why not trigonometric "constants"?

If your d is a constant, so is std::sin(d). A cross compiler is
allowed to pass on that, and not produce the exact bit pattern of the
target's 128-bit long double. It can postpone that until run-time (on
the proper harware).

So, it is a constant, but not a compile time constant.



Bo Persson


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
C/C++ language proposal: Change the 'case expression' from "integral constant-expression" to "integral expression" Adem C++ 42 11-04-2008 12:39 PM
C/C++ language proposal: Change the 'case expression' from "integral constant-expression" to "integral expression" Adem C Programming 45 11-04-2008 12:39 PM
const vector<A> vs vector<const A> vs const vector<const A> Javier C++ 2 09-04-2007 08:46 PM
error Message: "only const static integral data members can be initializedinside a class or struct" Susan Baker C++ 2 07-03-2005 12:29 PM
About static const members appearing in another static const definitions Rakesh Sinha C++ 4 01-13-2005 08:11 AM



Advertisments