floating-point literal cannot appear in a constant-expression

T

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

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
 
A

Alf P. Steinbach

* 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

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:
#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;
}
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.

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 :) )
 
J

James Kanze


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."

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.

And the initialization within the class requires an integral
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top