Re: initialization of a const static float data member in a class
On Jun 15, 3:39 am, "Alf P. Steinbach" <al...@start.no> wrote:
* James Kanze:
On Jun 14, 4:30 am, "Alf P. Steinbach" <al...@start.no> wrote:
* Ian Collins:
Alf P. Steinbach wrote:
* James Kanze:
I'm just curious, but do you have any examples where being
able to define the initialization in the class definition
(which is definitely a hack) would make some coding
simpler.
I can't see any example where it wouldn't?
One argument I've heard is differences between the
compilation host and target floating point representations.
42 is always 42, but 0.123*12345.678 may not have the same
representation on all hardware.
It's just a specious red herring argument.
Historically, it wasn't. And it wasn't a question of
representation, but actual value: 5*7 is equal to 35 always,
everywhere. The actual value of 1.2*3.4 depends on the floating
point representation, however.
Note that this very definitely was the motivation for not
allowing floating point arguments for templates. Given
something like:
template< double F > class T{} ;
do
T< 1.2*3.4 > t1 ;
T< 4.08 > t2 ;
have the same type or not?
Of course, this argument doesn't really apply to the initializer
of a static member.
Right. It's specious. :-)
Uh, note James, lately I've not had the drive I had earlier to
engage in all sorts of long-winded discussions.
I just make my points and if people don't grok 'em, well I
don't any longer feel any strong compulsion to enlighten them
-- let people be idiots, you can't change them, that's my new
motto! :-)
I go through phases like that myself. It causes a lot less
stress.
But I make exception for you since you're not in
ordinary people (idiot) class, but somewhere at opposite end
of scale. Just, still don't expect me to reply to all.
No worry. Much of what I posted was not really an attempt to
disagree with you, but to put things in historical perspective
for other readers: why the current situation is the way it is.
If we didn't have to deal with history, I'm not sure how we'd
specify the language today. But I'm fairly certain that the
language would be specified in a way to allow initializer values
to be specified in the class, and probably in a way to not
require an additional definition if they were specified. For
better or for worse, however, the current specification is a
result of history, and a history in which C compatibility and
the ability to work with classical C linkers was important.
[...]
The language currently does not have the concept of a constant
0.123*12345.678.
I think you mean "compile time constant".
More or less. Perhaps it would be more accurate to say that
there is no place in the standard which would require the
compiler to evaluate that expression.
Right. And irrelevant. Misleading though since we're talking
about (other) constants and it might seem to apply to those.
It doesn't.
It's just that with current rules it's a load of unnecessary
notation and complication and no guaranteed checking that
you've fulfilled the language's requirements.
Which current rule? That you have to define the variable if you
use it?
Yeah, that one. Plus the one limiting in-class initialization.
G++ certainly gives an error here, even if the variable has
an initializer. (Technically, of course, it is the linker
that gives the error, but error there is.)
It's not required to.
No. It's a violation of the one definition rule, which is
undefined behavior. I'm at home now, so I can only verify with
g++, but I'm pretty sure that Sun CC behaves similarly.
I've also just noticed that the current draft also modifies
this. In the standard, a definition is required if the variable
is used, period. In the latest draft I have at hand here, it is
required if the variable is used in a way that doesn't result in
an immediate lvalue-to-rvalue conversion, which corresponds
exactly to the behavior of the compilers I have at hand.
Now I see else-thread that purportedly C++0x will fix this.
Fix what? I have the impression that we are talking about
several different things here. I don't have the very latest
draft here, but from what I can see, all that has changed is
that you can now provide an initializer for any "const literal
type" (whatever that is---I'm guessing that it means a type for
which some literal exists). You still have to provide a
definition somewhere.
Yeah, that's stupid.
But with the above change, corresponds to the behavior of g++
and Sun CC (and probably most other compilers).
To date, as I said, I'm not aware of any proposal to change
this. And I don't feel competent to discuss the pros and cons
of a proposal that doesn't exist---I want to know exactly what
is being proposed, first.
Here's one possible proposal, off the cuff, so not sure if
compiles! :-)
The C++xx construction
struct A
{
static double const x = 1*2;
};
is to be treated as (i.e. compiler rewrites as) C++98 valid code
template< typename Dummy >
struct __A_x
{
static double const x;
};
template< typename Dummy >
double const __A_x<Dummy>::x = 1*2;
struct A: __A_x<void>
{
};
where __A_x is some generated globally unique name, and except
that if there is any way of generally detecting whether A has
a base class (dunno), then such way shall not detect the
presence of __A_x.
Well, that's hardly the language which would be used in the
standard, but it is a good proof of implementability (which is
also necessary---not that I doubted it, but you know how it is).
I rather liked Kai-Uwe's approach, although it still needs a
little work.
Since the rewritten code is valid C++98 code there's no
adjustment of one-definition-rule: it's still in effect as
before, and still rules.
What happens to code which defines the variable (as currently
required)? Does it suddenly become illegal?
If so, hurray (I haven't noticed that, but then I haven't
scrutinized the draft!) -- and if so, it sort of pulls the
rug under James' argument that
"For most of the members of the committee (and for all of the
other experts I know), [There is no imperative language based
reason to allow [these in-class definition initializations]].
The general feeling is that ideally, you shouldn't be able to
provide the initialization in the class definition at all"
You'll have to explain that one to me. There is no imperative
language based reason.
Yeah. And as mentioned earlier that applies to 'for', 'do' and
'while' as well. Your argument was that in spite of that,
most members of the committee and all other experts you know
had embraced the fallacious argument, so that they would not
be likely to consider anything like reason, but with some
support in C++0x draft, although still keeping separate
definition sillyness, that argument has very little force left
it in -- when they can be moved to go most of the way,
perhaps they can be moved to go the teeny tiny little distance
left also?
:-)
I think you misunderstood my claim. Given the current object
model (and the one definition rule, etc.), allowing any
initializer is a hack. C++ didn't allow it even for integers
for the longest time, and I'm aware of some experts who don't
like that exception (for whatever reasons). The "imperative
language based reasons" provided the impetus which made the hack
acceptable. (It's not like for, do or while, because they
aren't felt to be hacks.)
Of course, there is a huge distance left for the Most General
Solution, that of introducing something akin to 'inline' for
/data/. :-) But since we don't really really need that MGS in
practice, no need to waste time convincing.
Actually, it might be a good idea. It expresses exactly what is
really wanted, and solves the problem with the one definition
rule.
Note that in the current draft, you can declare an inline
function to be a constexpr (with serious limitations as to what
you can do in the function, of course); even class types can be
constant expressions, if their non-copy constructors are
constexpr. So IMHO, there is a (new) very strong argument for
providing some sort of mechanism where you don't have to provide
a definition elsewhere: if
struct S { constexpr static inline int f() { return 43 ; } } ;
is legal, and you don't have to provide a definition for f
elsewhere, why should you not be able to do the same thing for a
data object?
Now if only there were enough time to discuss it more
thoroughly. (I seriously like the "inline" idea. The parallel
with functions appeals to me. I obviously can't speak for
the committee on this, but it also sounds like something simple
enough to have a chance of still slipping in. With a strong
argument on grounds of orthogonality: it works with functions,
why not with data members.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34