[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Don't initialize constexpr variable with std::ldexp()

From: Greg Chicares
Subject: Re: [lmi] Don't initialize constexpr variable with std::ldexp()
Date: Mon, 24 Apr 2017 15:25:48 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.6.0

On 2017-04-24 12:24, Vadim Zeitlin wrote:
>  Both clang and MSVC refuse to compile the current lmi sources because of a
> constexpr variable being initialized with a non-constexpr std::ldexp() call.

[...because std::ldexp() is not declared 'constexpr'...]

>  They both seem quite correct with respect to the current language
> standard, while gcc seems to implement the extensions proposed in
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0533r0.pdf
> and which might become available in a later language version, but we can't
> rely on them yet.

[...these improvements are obvious, but not trivial because of 'errno'...]

>  So the attached patch simply replaces "constexpr" with in "limit"
> declaration with "const" to fix compilation with clang and MSVC (while
> still continuing to compile with gcc, of course).

Committed. I'll push it today.

With this patch, does the 'bourn_cast_test.cpp' unit test compile and
report zero errors with these other two compilers?

>  Notice that I didn't change the "static" keyword even though I'm not
> really sure if it's appropriate to use it here and, moreover, if I'm quite
> sure that it's not useful to use it with "constexpr" in the
> is_twos_complement declaration just below. Maybe this should be addressed
> too...

*With* this patch, I should think that 'static' is beneficial.

  const From limit = std::ldexp(From(1), to_traits::digits);

This is what we used to call an 'auto' variable. Notionally, each time the
containing function is called, the compiler allocates storage for it, calls
ldexp(), and frees the storage upon leaving the scope. A compiler can do
something smarter than that, but we aren't giving it any hint that it should.

  static const From limit = std::ldexp(From(1), to_traits::digits);

Using storage class 'static' instructs the compiler to initialize 'limit'
once and only once, and preserve that value across multiple calls to the
containing function. That's what we want, but without 'static' we can't be
sure that's what we get.


  static constexpr From limit = std::ldexp(From(1), to_traits::digits);

In a dialect that includes P0533R0 [cited above], 'constexpr' is legal here,
and the question arises whether we should use 'static' as well. 'constexpr'
already requires that the value be computed at compile time (and used every
time the function is called), which is the reason we used 'static' above.
Thus, there's no reason to use 'static' in addition to 'constexpr' here.

But is there any reason *not* to use 'static' here? C++11 [3.7.1/2] says:
| If a variable with static storage duration has initialization or a
| destructor with side effects, it shall not be eliminated even if it
| appears to be unused

I'm not entirely sure whether to parse that as
  has (initialization) or (a destructor with side effects)
  has (initialization or a destructor) (with side effects)
I assume it's the latter (because any static variable "has initialization"),
so that initialization-with-side-effects prevents a variable from being
eliminated. Given the assumption that the dialect includes P0533R0, an
error such as this:
  constexpr double foo = std::ldexp(DBL_MAX, INT_MAX);
would be a compile error; but if ldexp() is used in a constexpr context
that is not erroneous, then apparently the errno and FE_OVERFLOW side
effects cannot occur...so this is not initialization-with-side-effects,
and a 'static constexpr' variable can be eliminated.

On the other hand, we can't be sure compilers will behave exactly that way,
and P0533R0 does not propose any emendation to the standard that would
vitiate 3.7.1/2 . Following that line of thought, we might say that here:
  static constexpr From limit = std::ldexp(From(1), to_traits::digits);
'static' doesn't suggest "initialize once and only once", because 'constexpr'
already prevents repetitive calls to ldexp()...so 'static', if written here
at all, can only be a hint (or an imperative command) that the compiler
should not eliminate 'limit'; but that is not what we want, and therefore
it would be better not to declare a variable 'static constexpr'.

Is that your reasoning for suggesting s/static constexpr/static/g throughout
this header? Is there any other consideration that I've overlooked?

reply via email to

[Prev in Thread] Current Thread [Next in Thread]