By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,645 Members | 1,125 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,645 IT Pros & Developers. It's quick & easy.

initialization of a const static float data member in a class

P: n/a
Is there a technical reason why one can't initialize a cost static non-
integral data member in a class?
Jun 27 '08 #1
Share this Question
Share on Google+
15 Replies


P: n/a
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.

--
Ian Collins.
Jun 27 '08 #2

P: n/a
On Jun 13, 10:07*am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
For you. *For most of the members of the committee (and for all
of the other experts I know), it does. *The general feeling is
that ideally, you shouldn't be able to provide the
initialization in the class definition at all---it's an ugly
hack.

[snip]

Actually, I wonder where that assesment comes from. In my coding style (I do
almost exclusively templated code), all code goes into header files. I
rarely ever split declarations from definitions. Being forced to do that
for static const members creates an imbalance in coding style that makes
the non-hack ugly and the hack natural.

I don't think it is a good idea for the standard to legislate style; and for
templated code, the issue is more or less entirely a matter of style.
C++09 will allow the in-definition intialization of any static class
member of a "literal" type - including floating point types. After
all, it probably doesn't make much sense to most C++ programmers, that
a floating point constant in a header file is OK outside of a class
definition - but suddenly becomes a problem when moved inside a class
definition:

// header.h

const float kFloatConstant = 1.0f; // OK

class A
{
public:
static float kFloatConstant = 2.0f; // Error - but OK in C++09
};

Greg
Jun 27 '08 #3

P: n/a
On Jun 13, 10:07*am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
James Kanze wrote:.
For you. *For most of the members of the committee (and for all
of the other experts I know), it does. *The general feeling is
that ideally, you shouldn't be able to provide the
initialization in the class definition at all---it's an ugly
hack.

[snip]

Actually, I wonder where that assesment comes from. In my coding style (I do
almost exclusively templated code), all code goes into header files. I
rarely ever split declarations from definitions. Being forced to do that
for static const members creates an imbalance in coding style that makes
the non-hack ugly and the hack natural.

I don't think it is a good idea for the standard to legislate style; and for
templated code, the issue is more or less entirely a matter of style.
C++09 will allow the in-definition initialization of any static class
member of a "literal" type - including floating point types. After
all, it probably does not make much sense to most C++ programmers that
a constant floating point variable may be declared in a header file
(outside of a class) - but may not be declared in a header file
(inside of a class):

// header.h

const float kFloatConstant = 1.0f; // OK

class A
{
public:
static const float kFloatConstant = 2.0f; // Error - but OK in C+
+09
}

Greg

Jun 27 '08 #4

P: n/a
Alf P. Steinbach 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.
One case would be a cross-compiler.
After all, there's nothing preventing us from defining these constants
with the current language.
That's true, but I don't think they are classed as compile time
constants (not that is makes much difference for a floating point value)
where as an integer type is.

A quick check with Sun CC shows "const float ff = 42.0*42.0;" is
calculated at run time with all but the most relaxed architecture and
floating point compiler options.
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.

Now I see else-thread that purportedly C++0x will fix this.
There is a case for consistency.
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"
:)

A always thought the exception for integer types was to remove the
necessity for the old enum hack compile time constant (for an array size
for instance). This was a pain in pre-standard compilers, just as it is
in C today.

It looks like the exception is about to become the rule!

--
Ian Collins.
Jun 27 '08 #5

P: n/a
On Jun 14, 1:14 am, Greg Herlihy <gre...@mac.comwrote:
On Jun 13, 10:07 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
James Kanze wrote:.
For you. For most of the members of the committee (and
for all of the other experts I know), it does. The
general feeling is that ideally, you shouldn't be able to
provide the initialization in the class definition at
all---it's an ugly hack.
[snip]
Actually, I wonder where that assesment comes from. In my
coding style (I do almost exclusively templated code), all
code goes into header files. I rarely ever split
declarations from definitions. Being forced to do that for
static const members creates an imbalance in coding style
that makes the non-hack ugly and the hack natural.
I don't think it is a good idea for the standard to
legislate style; and for templated code, the issue is more
or less entirely a matter of style.
C++09 will allow the in-definition initialization of any
static class member of a "literal" type - including floating
point types. After all, it probably does not make much sense
to most C++ programmers that a constant floating point
variable may be declared in a header file (outside of a class)
- but may not be declared in a header file (inside of a
class):
// header.h
const float kFloatConstant = 1.0f; // OK
class A
{
public:
static const float kFloatConstant = 2.0f; // Error - but OK in C+
+09
}
There's one very big difference between the two: every source
which includes the header has a separate instance of
::kFloatConstant, but there is only one instance of
::A::kFloatConstant in the entire program. And of course, the
fact that you still have to define A::kFloatConstant somewhere.

In many ways, the correct analogy would be:

extern float const kFloatConstant ;
// declaration, not definition

class A
{
public:
static float const kFloatConstant ;
// declaration, not definition
} ;

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #6

P: n/a
On Jun 14, 4:30 am, "Alf P. Steinbach" <al...@start.nowrote:
* 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. But historically, C has made a point of not
requiring a cross compiler to implement the target floating
point arithmetic---there is currently no where in the language
where the compiler is required to do floating point arithmetic.
After all, there's nothing preventing us from defining these
constants with the current language.
The language currently does not have the concept of a constant
0.123*12345.678.
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? 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.)
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.

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.
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. Once you have the hack, there's a good
argument (orthogonality) for extending it to all types. And of
course, *ideally*, we wouldn't need the hack (but as we all
know, C++ is based more on pragmatics than on ideals). (But to
be honest, I should have qualified the "most". I've not really
spoken to that many on the subject, so the "most" really only
applies to a small sampling.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #7

P: n/a
On Jun 14, 4:50 am, Ian Collins <ian-n...@hotmail.comwrote:

[...]
A always thought the exception for integer types was to remove
the necessity for the old enum hack compile time constant (for
an array size for instance). This was a pain in pre-standard
compilers, just as it is in C today.
That was the original motivation.
It looks like the exception is about to become the rule!
I suspect (but I've not actually talked to the people involved)
that the motivation for extending it to "literal types" is
orthogonality. While allowing it for anything is certainly a
bit of a hack, allowing it for int and not for double seems
rather arbitrary too.

For the rest, it's still a hack: the declaration in the class
itself is still not a definition, and you still have to provide
a definition elsewhere. (And presumably, compilers will still
complain if you use the variable and don't provide a
declaration---with a possible exception if the use involves an
immediate lvalue to rvalue conversion of an integral type.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #8

P: n/a
James Kanze wrote:
>
For the rest, it's still a hack: the declaration in the class
itself is still not a definition, and you still have to provide
a definition elsewhere. (And presumably, compilers will still
complain if you use the variable and don't provide a
declaration---with a possible exception if the use involves an
immediate lvalue to rvalue conversion of an integral type.)
Interesting point. With current compilers, a declaration is only
required if the address of a static const member is used. Presumably
the value is a compile time constant, so the declaration is not required
in immediate uses.

With a floating point type, this will not be the case. So which rules
will apply in the new standard? If a declaration is required for all
uses, plenty of existing code will break.

--
Ian Collins.
Jun 27 '08 #9

P: n/a
On Jun 14, 3:46Â*pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
James Kanze wrote:
For the moment, I don't know exactly what the counter-proposal
is, so it's hard to argue against it, or agree with it. Â*If the
proposal is that the declaration in the class should be a
definition (and thus, that you don't need a definition
elsewhere), then I'm radically against it; such a rule would
mean that things like:
Â* Â* static int someArray[] ;
would be illegal (since a definition requires a complete type),
and that you'd always have to provide the initializer in the
class (and most of the time, you really don't want to).

So let's try to reword [9.4.2/2]:

Â* The declaration of a static data member in its class definition is not a
Â* definition and may be of an incomplete type other than cv-qualifiedvoid
Â* unless it specifies an initializer, in which case it is a definition and
Â* the type shall be complete. If the declaration is not a definition,the
Â* definition for a static data member shall appear in a namespace scope
Â* enclosing the member?s class definition. In the definition at namespace
Â* scope, the name of the static data member shall be qualified by itsclass
Â* name using the :: operator. The initializer expression in the definition
Â* of a static data member is in the scope of its class (3.3.6).

What about that?
Actually, I think the next paragraph is the more interesting one:

"If a static data member is of const literal type, its declaration in
the class definition can specify a constant-initializer. A static data
member of literal type can be declared in the class definition with
the constexpr specifier; if so, its declaration shall specify a
constant-initializer. In both these cases, the member may appear in
integral constant expressions. 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."[§9.4/3 N2606]

The Draft also defines a "literal" type:

A type is a literal type if it is:

— a scalar type;

or

— a class type (clause 9) with
— a trivial copy constructor,
— a trivial destructor,
— at least one constexpr constructor
other than the copy constructor,
— no virtual base classes,
and
— all non-static data members and base classes
of literal types;
or

— an array of literal type. [§3.9/10 N2606]

So there seem to be two ways in C++09 to provide an in-class
initializer for a const static class member: either declare the const
static member with a constexpr specifier, or (the more old-fashioned
way) with a simple "static const" specifier.

Note that when the class member is defined with a constexpr specifier,
no corresponding member definition outside of the class may appear.
Even in the "const" case, an out-of-class definition is needed only if
the member is "used" in the program (which essentially means - only if
its address is taken). Otherwise, the declaration and "initialization"
of the const static member inside of the class definition - is enough.

Greg

Jun 27 '08 #10

P: n/a
On Jun 14, 3:41*pm, Ian Collins <ian-n...@hotmail.comwrote:
James Kanze wrote:
For the rest, it's still a hack: the declaration in the class
itself is still not a definition, and you still have to provide
a definition elsewhere. *(And presumably, compilers will still
complain if you use the variable and don't provide a
declaration---with a possible exception if the use involves an
immediate lvalue to rvalue conversion of an integral type.)

Interesting point. *With current compilers, a declaration is only
required if the address of a static const member is used. *Presumably
the value is a compile time constant, so the declaration is not required
in immediate uses.

With a floating point type, this will not be the case. *So which rules
will apply in the new standard? *If a declaration is required for all
uses, plenty of existing code will break.
No, the innitialization of static const floating point class members
will not be treated any differently than the way that in-class
initialization of static const integral class members is handled in
the current Standard. Essentially, no out-of-class definition will be
needed for a const static class member (of a literal type) that has
been initialized within a class declaration. Unless, of course, the
program "uses" that class member.

According to the Draft, a variable is "used" if:

An object or non-overloaded function whose name appears as a
potentially-evaluated expression is "used" unless it is an object that
satisfies the requirements for appearing in a constant expression
(5.19) and the lvalue-to-rvalue conversion (4.1) is immediately
applied.[§3.2/2 N2606]

Note that C99 has supported constant floating point expressions for
over eight years now, so in some ways, C++ is simply catching up.

Greg

Jun 27 '08 #11

P: n/a
Greg Herlihy wrote:
On Jun 14, 3:41 pm, Ian Collins <ian-n...@hotmail.comwrote:
>James Kanze wrote:
>>For the rest, it's still a hack: the declaration in the class
itself is still not a definition, and you still have to provide
a definition elsewhere. (And presumably, compilers will still
complain if you use the variable and don't provide a
declaration---with a possible exception if the use involves an
immediate lvalue to rvalue conversion of an integral type.)
Interesting point. With current compilers, a declaration is only
required if the address of a static const member is used. Presumably
the value is a compile time constant, so the declaration is not required
in immediate uses.

With a floating point type, this will not be the case. So which rules
will apply in the new standard? If a declaration is required for all
uses, plenty of existing code will break.

No, the innitialization of static const floating point class members
will not be treated any differently than the way that in-class
initialization of static const integral class members is handled in
the current Standard. Essentially, no out-of-class definition will be
needed for a const static class member (of a literal type) that has
been initialized within a class declaration. Unless, of course, the
program "uses" that class member.

According to the Draft, a variable is "used" if:

An object or non-overloaded function whose name appears as a
potentially-evaluated expression is "used" unless it is an object that
satisfies the requirements for appearing in a constant expression
(5.19) and the lvalue-to-rvalue conversion (4.1) is immediately
applied.[§3.2/2 N2606]
OK, thanks.
Note that C99 has supported constant floating point expressions for
over eight years now, so in some ways, C++ is simply catching up.
So has C++, just not for class members.

--
Ian Collins.
Jun 27 '08 #12

P: n/a
On Jun 15, 12:46 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
James Kanze wrote:
[...]
For the moment, I don't know exactly what the
counter-proposal is, so it's hard to argue against it, or
agree with it. If the proposal is that the declaration in
the class should be a definition (and thus, that you don't
need a definition elsewhere), then I'm radically against it;
such a rule would mean that things like:
static int someArray[] ;
would be illegal (since a definition requires a complete
type), and that you'd always have to provide the initializer
in the class (and most of the time, you really don't want
to).
So let's try to reword [9.4.2/2]:
The declaration of a static data member in its class
definition is not a definition and may be of an incomplete
type other than cv-qualified void unless it specifies an
initializer, in which case it is a definition and the type
shall be complete. If the declaration is not a definition,
the definition for a static data member shall appear in a
namespace scope enclosing the member?s class definition. In
the definition at namespace scope, the name of the static
data member shall be qualified by its class name using the
:: operator. The initializer expression in the definition of
a static data member is in the scope of its class (3.3.6).
What about that?
It's a start. Of course, you'll also need something in §3.2.
Otherwise, a header which contains something like:

struct S { static int i = 43 ; } ;

will cause undefined behavior if it is included in more than one
translation unit.

Also, consider the issues of backwards compatibility; your
suggestion would make a lot of currently conforming code
illegal (since the previously required definition would suddenly
become a duplicate definition).

But those problems should be solvable as well. The real problem
is, of course, that on one has presented such a proposition to
the committee (and I suspect that it is too late now---we should
be very, very close to a CD, if the next version is really to be
C++0x, and not C++1x).
I can understand Alf's desire that all types (and not just
integral types) can have an initializer, and that shouldn't be
too hard to specify nor to implement. With regards to his
desire that you not need the separate definition, however, I'd
want to see the actual proposal. I understand the desire, but I
fear that it would require significant rework of the meaning of
definitions and declarations, which in turn is very likely to
have effects elsewhere.
In my coding style (I do almost exclusively templated code),
all code goes into header files. I rarely ever split
declarations from definitions.
I'm not sure I understand, and I don't quite see what templates
have to do with it. Whether the definition is in the header
file (or a file included from the header file) or in some
separate source file doesn't really change much.
I think, you misunderstood what I meant by splitting declarations and
definitions. I usually write
template < typename T >
class some_class {
void some_method ( some_type some_arg ) {
// implementation
}
};
instead of
template < typename T >
class some_class {
some_result_type some_method ( some_type some_arg );
};
template < typename T >
some_class<T>::some_result_type
some_class<T>::some_method ( some_class<T>::some_type some_arg ) {
// implementation
}
You mean that you make almost all of your functions inline?

In my work, it is normal to insist that the implementations be
in a separate file (even if, in the case of templates, this file
is included by the header). It's more or less a basic principle
if you're working in large systems (or more strictly speaking,
if there are more than two or three people working on the
application); you don't want the interface to accidentally
change after some bug fix in the implementation. (If you've
never accidentally changed something you didn't mean to, you're
a better typist than I am. Where as it's impossible to
accidentally change something in a file you haven't checked
out.)
Being forced to do that for static const members creates an
imbalance in coding style that makes the non-hack ugly and the
hack natural.
I don't think it is a good idea for the standard to legislate
style; and for templated code, the issue is more or less
entirely a matter of style.
I'm afraid I don't see where templates change anything.
They don't change the technical side of things. However, as
you can see above, the separation of the definition from the
declaration becomes quite wordy for templates.
There's a fair amount of redundance even for non-templates:-). A
good editor helps, but there's still a fair bit of typing to do.
Moreover, it has very little return for the effort since
compilers by and large do not support export and the main
technical reasons to hide definitions do not apply. That
influences coding style.
Even without export, I use separate files. For one, it will
make migration to a compiler which supports export simpler, and
for the other, it still keeps the implementation in a separate
file from the interface---essential when you have more than a
few people working on the same code base (but I agree that
without export, templates are pretty much unusable at the
application level).
But whatever. Until there is a concrete proposal, I don't
know what I'm considering.
See above.
Next step: get it to the committee. If you'd like, write it up
in the format of a formal proposal (with motivation, impact, and
potentially discussion of other alteratives, and why they are
rejected), and send it to me by private email, and I'll take
charge of presenting it. But don't get your hopes up too
much---two or three years ago, I think it would have found a
good deal of interest, but I fear that it's a bit too late at
present. (On the other hand, it's possible that something else
will come up which delays the standard, and someone on the
committee might take advantage of that to slip it through.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #13

P: n/a
On Jun 15, 3:39 am, "Alf P. Steinbach" <al...@start.nowrote:
* James Kanze:
On Jun 14, 4:30 am, "Alf P. Steinbach" <al...@start.nowrote:
* 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:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #14

P: n/a
James Kanze wrote:
On Jun 15, 12:46 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>James Kanze wrote:

[...]
For the moment, I don't know exactly what the
counter-proposal is, so it's hard to argue against it, or
agree with it. If the proposal is that the declaration in
the class should be a definition (and thus, that you don't
need a definition elsewhere), then I'm radically against it;
such a rule would mean that things like:
static int someArray[] ;
would be illegal (since a definition requires a complete
type), and that you'd always have to provide the initializer
in the class (and most of the time, you really don't want
to).
>So let's try to reword [9.4.2/2]:
> The declaration of a static data member in its class
definition is not a definition and may be of an incomplete
type other than cv-qualified void unless it specifies an
initializer, in which case it is a definition and the type
shall be complete. If the declaration is not a definition,
the definition for a static data member shall appear in a
namespace scope enclosing the member?s class definition. In
the definition at namespace scope, the name of the static
data member shall be qualified by its class name using the
:: operator. The initializer expression in the definition of
a static data member is in the scope of its class (3.3.6).
>What about that?

It's a start. Of course, you'll also need something in §3.2.
Otherwise, a header which contains something like:

struct S { static int i = 43 ; } ;

will cause undefined behavior if it is included in more than one
translation unit.
True.
Also, consider the issues of backwards compatibility; your
suggestion would make a lot of currently conforming code
illegal (since the previously required definition would suddenly
become a duplicate definition).
Actually, I was more thinking about what people could have done 20 years
ago. Off the top of my head, I don't see how backward compatibility can be
achieved.
But those problems should be solvable as well. The real problem
is, of course, that on one has presented such a proposition to
the committee (and I suspect that it is too late now---we should
be very, very close to a CD, if the next version is really to be
C++0x, and not C++1x).
Probably it is not just too late but also not really worth the hassle. After
all, for the technical issues (inclusion of constants in header files) work
arounds do exists and all other issues are strictly matters of style and
taste.
I can understand Alf's desire that all types (and not just
integral types) can have an initializer, and that shouldn't be
too hard to specify nor to implement. With regards to his
desire that you not need the separate definition, however, I'd
want to see the actual proposal. I understand the desire, but I
fear that it would require significant rework of the meaning of
definitions and declarations, which in turn is very likely to
have effects elsewhere.
>In my coding style (I do almost exclusively templated code),
all code goes into header files. I rarely ever split
declarations from definitions.
I'm not sure I understand, and I don't quite see what templates
have to do with it. Whether the definition is in the header
file (or a file included from the header file) or in some
separate source file doesn't really change much.
>I think, you misunderstood what I meant by splitting declarations and
definitions. I usually write
> template < typename T >
class some_class {
void some_method ( some_type some_arg ) {
// implementation
}
};
>instead of
> template < typename T >
class some_class {
some_result_type some_method ( some_type some_arg );
};
> template < typename T >
some_class<T>::some_result_type
some_class<T>::some_method ( some_class<T>::some_type some_arg ) {
// implementation
}

You mean that you make almost all of your functions inline?
Yup.
In my work, it is normal to insist that the implementations be
in a separate file (even if, in the case of templates, this file
is included by the header). It's more or less a basic principle
if you're working in large systems (or more strictly speaking,
if there are more than two or three people working on the
application); you don't want the interface to accidentally
change after some bug fix in the implementation. (If you've
never accidentally changed something you didn't mean to, you're
a better typist than I am. Where as it's impossible to
accidentally change something in a file you haven't checked
out.)
[snip]

I agree that redundancy is good. It safeguards against accidental changes.
However, I think that what one really wants is not a redundancy within the
implementation (.h vs .cc) but redundancy that comes from the existence of
documentation. Ideally, I would have a tool that checks whether my
documented interface matches the implemented interface. I feel that the
current use of the compiler to ensure header and source file match is a
crutch that encourages confusing the header file for documentation.
Best

Kai-Uwe Bux
Jun 27 '08 #15

P: n/a
On Jun 15, 5:08 pm, "Alf P. Steinbach" <al...@start.nowrote:
* James Kanze:
On Jun 15, 3:39 am, "Alf P. Steinbach" <al...@start.nowrote:
[...]
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?
Couldn't, so this change would have to clean up that
untidyness (see, I'm also moderating my language! Heh) where
something with an initializer is currently regarded as a pure
declaration.
I'm not really sure I understand which direction you're arguing
here. You say (correctly, IMHO) that code which currently
provides the separate definition couldn't suddenly become
illegal, but they you want to clean up the untidiness in which
something with an initializer is a pure declaration (which is,
of course, what I've been calling a hack). I fear that no
matter how you do it, you're going to have to introduce another
hack to avoid breaking existing code.
That's, oops, almost introduced some Language there, but it's
a conceptual inconsistency that has to be explained to
everyone who reaches that level of understanding. Fixing that,
removing that special case aberration, so then "has
initializer" = "is definition", so that what looks like a
definition then is a definition just like everywhere else in
the language, then those silly-definitions that look like pure
declarations can just be pure declarations, and allowed as
redundant declarations for backwards compatibility.
OK. That sounds like a reasonably good fix for the problem.
(Not that they look like pure declarations. Something like "int
A::x ;" is a definition if it appears at namespace scope. Even
if A is a namespace, and not a class.)
So, this would also clean up the conceptual a bit!
By the way, since you liked "inline data" idea, that's
compatible with above proposal. But it's more general since it
would describe/conceptualize the above as an implicit inline
definition, just like member functions that are /defined/ in
the class definition. And then would presumably also allow
'inline' explicitly applied to data, complete orthogonality
for that.
Yes. That's probably what I liked most about it: its
orthogonality.
Cheers,
- Alf (who liked orhtogonal MC68000 much better than
special-cases i80386).
Didn't everyone?

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #16

This discussion thread is closed

Replies have been disabled for this discussion.