Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

floating-point literal cannot appear in a constant-expression

342 views
Skip to first unread message

TimC

unread,
Mar 6, 2009, 3:55:58 AM3/6/09
to
g++ 4.x -pedantic doesn't allow me to do this:

static const long int DOME_WANDER = int(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

(minimal code is below)

in a class declaration, and gives:
In file included from TcsEncoderTask.C:232:
AbsIncPositionTracker.h:189: error: floating-point literal cannot appear in a constant-expression

First off, is that truly illegal code (TcsAbsDomeToArcsec and
TcsIncDomeToArcsec are just #defines of floats) according to the
standards?

And secondly, if this is truly illegal and not just a mundane bug in
gcc, tell me, what would be the point of illegalising that, and what
do I do to get around it? Surely a cast (it's been a while since I've
done C/C++, so I tried several different casts, none of which worked)
is sufficient to convince both a compiler and a language lawyer that
yes, I know it's a float, but an int is perfectly acceptable for my
purposes? Initialising DOME_WANDER to be a pure int not calculated
from those above floats would be fragile and a serious pain.


Absolutely minimal code:
> cat asd.C
#define TcsAbsDomeToArcsec (10.5469 * 60.0)
#define TcsIncDomeToArcsec 0.150

class AbsIncPositionTracker {

static const long int DOME_WANDER = (long int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);
};

int main (int, char**)
{
return 0;
}
> g++ -c -ansi -Wall -W -pedantic asd.C
asd.C:6: error: floating-point literal cannot appear in a constant-expression
asd.C:6: error: floating-point literal cannot appear in a constant-expression
asd.C:6: error: floating-point literal cannot appear in a constant-expression
asd.C:6: error: floating-point literal cannot appear in a constant-expression

--
TimC
[advice on riding in traffic:] make eye contact with drivers at every
possible opportunity. If they make eye contact, they'll feel worse
about running over you. -- Davidm in aus.bicycle

Alf P. Steinbach

unread,
Mar 6, 2009, 5:39:29 AM3/6/09
to
* TimC:

<comeau>
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 6: error: expression must have integral or enum type


static const long int DOME_WANDER = (long
int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

^

"ComeauTest.c", line 6: error: expression must have integral or enum type


static const long int DOME_WANDER = (long
int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

^

"ComeauTest.c", line 6: error: expression must have integral or enum type


static const long int DOME_WANDER = (long
int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

^

"ComeauTest.c", line 6: error: expression must have integral or enum type


static const long int DOME_WANDER = (long
int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

^

4 errors detected in the compilation of "ComeauTest.c".
</comeau>


Formally this is due to §5.19/1, which states that "An /integral constant-
expression/ can involve only literals (2.13), enumerators, const variables or
static data members of integral or enumeration types initialized with constant
expressions (8.5), non-type template parameters of integral or enumeration
types, and sizeof expressions. Floating literals can appear only if they are
cast to integral or enumeration types." Further on it mentions that you can't
use pointers, references, or comma expressions, not even function calls.

But as far as I know it's only a political thing, same no-good reason that you
can't initialize a floating point class static in that way.

Because you can express the same just with a little different syntax:

<code>
namespace tcs {
double const absDomeToArcsec = 10.5469 * 60.0;
double const incDomeToArcsec = 0.150;
} // namespace tcs

template< typename Dummy >
struct DomeWander_
{
static long const domeWander;
};

template< typename Dummy >
long const DomeWander_<Dummy>::domeWander =
(long int)(tcs::absDomeToArcsec*1.25/tcs::incDomeToArcsec);

class AbsIncPositionTracker
: private DomeWander_<void> // domeWander
{};

int main ()
{}
</code>

The difference is that when the value isn't specified in the in-class
declaration, it's no longer restricted to /integral constant-expression/.

Of course this kind of code is a bit unwieldy when not wrapped in suitable macros...


Cheers & hth.,

- Alf (yet one more possible inventor of the template const idiom :-) )


--
Due to hosting requirements I need visits to [http://alfps.izfree.com/].
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!

James Kanze

unread,
Mar 7, 2009, 4:51:02 AM3/7/09
to
On Mar 6, 11:39 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * TimC:
> > g++ 4.x -pedantic doesn't allow me to do this:

> > static const long int DOME_WANDER =
> > int(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

> > (minimal code is below)

> > in a class declaration, and gives:
> > In file included from TcsEncoderTask.C:232:
> > AbsIncPositionTracker.h:189: error: floating-point literal cannot appear in a constant-expression

The message is wrong: it should be "floating-point literal
cannot appear in an integral constant-expression unless it is
immediately converted to integral or enumeration type."

> > First off, is that truly illegal code (TcsAbsDomeToArcsec
> > and TcsIncDomeToArcsec are just #defines of floats)
> > according to the standards?

Yes.

> > And secondly, if this is truly illegal and not just a
> > mundane bug in gcc, tell me, what would be the point of
> > illegalising that, and what do I do to get around it?

The motivation was not to require cross-compilers to implement
the floating point arithmetic of the target machine. Without
implementing the exact floating point arithmetic of the target
machine, the value might not be the same as if the expression
was evaluated at runtime.

IMHO, whether this is a valid motivation is arguable, given that
the exact results of the expression at runtime are allowed to
vary.

> > Surely a cast (it's been a while since I've done C/C++, so I
> > tried several different casts, none of which worked) is
> > sufficient to convince both a compiler and a language lawyer
> > that yes, I know it's a float, but an int is perfectly
> > acceptable for my purposes? Initialising DOME_WANDER to be
> > a pure int not calculated from those above floats would be
> > fragile and a serious pain.

> > Absolutely minimal code:
> >> cat asd.C
> > #define TcsAbsDomeToArcsec (10.5469 * 60.0)
> > #define TcsIncDomeToArcsec 0.150

> > class AbsIncPositionTracker {

> > static const long int DOME_WANDER = (long int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

And the initialization within the class requires an integral
constant expression.

> > };
>
> > int main (int, char**)
> > {
> > return 0;
> > }
> >> g++ -c -ansi -Wall -W -pedantic asd.C
> > asd.C:6: error: floating-point literal cannot appear in a constant-expression
> > asd.C:6: error: floating-point literal cannot appear in a constant-expression
> > asd.C:6: error: floating-point literal cannot appear in a constant-expression
> > asd.C:6: error: floating-point literal cannot appear in a constant-expression

> <comeau>
> Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
> Copyright 1988-2008 Comeau Computing. All rights reserved.
> MODE:strict errors C++ C++0x_extensions

> "ComeauTest.c", line 6: error: expression must have integral or enum type
> static const long int DOME_WANDER = (long
> int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

> "ComeauTest.c", line 6: error: expression must have integral or enum type
> static const long int DOME_WANDER = (long
> int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

> "ComeauTest.c", line 6: error: expression must have integral or enum type
> static const long int DOME_WANDER = (long
> int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

> "ComeauTest.c", line 6: error: expression must have integral or enum type
> static const long int DOME_WANDER = (long
> int)(TcsAbsDomeToArcsec*1.25/TcsIncDomeToArcsec);

> 4 errors detected in the compilation of "ComeauTest.c".
> </comeau>

> Formally this is due to §5.19/1, which states that "An
> /integral constant- expression/ can involve only literals
> (2.13), enumerators, const variables or static data members of
> integral or enumeration types initialized with constant
> expressions (8.5), non-type template parameters of integral or
> enumeration types, and sizeof expressions. Floating literals
> can appear only if they are cast to integral or enumeration
> types." Further on it mentions that you can't use pointers,
> references, or comma expressions, not even function calls.

FWIW: this is being extended. I'm pretty sure, for example,
that certain functions (declared constexpr) will be allowed. I
don't know too much about what else, however.

> But as far as I know it's only a political thing, same no-good
> reason that you can't initialize a floating point class static
> in that way.

More historical than political, I think. There are really two
separate issues: the fact that the initialization expression in
this context must be an integral constant expression, and the
fact that floating point arithmetic cannot be used in an
integral constant expression.

> Because you can express the same just with a little different
> syntax:

A little:-)?

> <code>
> namespace tcs {
> double const absDomeToArcsec = 10.5469 * 60.0;
> double const incDomeToArcsec = 0.150;
> } // namespace tcs

> template< typename Dummy >
> struct DomeWander_
> {
> static long const domeWander;
> };

> template< typename Dummy >
> long const DomeWander_<Dummy>::domeWander =
> (long int)(tcs::absDomeToArcsec*1.25/tcs::incDomeToArcsec);

> class AbsIncPositionTracker
> : private DomeWander_<void> // domeWander
> {};

> int main ()
> {}
> </code>

> The difference is that when the value isn't specified in the
> in-class declaration, it's no longer restricted to /integral
> constant-expression/.

That would cover his minimal example. It's worth noting however
that in this case, domeWander is not an integral constant
expression; it can't be used as an array bounds, for example
(and theoretically, at least, you could access it before it was
initialized, and read 0). I don't know if that's a problem in
his actual code, however.

--
James Kanze (GABI Software) email:james...@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

0 new messages