lmi
[Top][All Lists]
Advanced

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

[lmi] Should lmi use 'consteval' yet?


From: Greg Chicares
Subject: [lmi] Should lmi use 'consteval' yet?
Date: Sun, 9 May 2021 14:14:13 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.9.0

Vadim--This isn't at all urgent. I'm just curious.

I was about to commit a 'currency.hpp' change like this...

--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
+/// Zero cents as a compile-time constant.
 ///
+/// This particular value occurs so often that it merits a terse name,
+/// no wider than '0.0'. Unlike '0_cents', 'C0' can be used in a
+/// context that requires a compile-time constant; otherwise, both
+/// perform equally well in optimized builds.
 
 inline constexpr currency C0 = {};
--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--

...when I decided to test that "Unlike '0_cents'..." part, and found that
it doesn't seem to be true, at least not with gcc-10. (I still like 'C0' for
terseness, but '0_cents' really does seem to be a compile-time constant.)

Using latest lmi HEAD, I was surprised that I can do this (using std::array
to test for compile-time-constant-ness--instead of C arrays, in case the
compiler offers variable-length arrays):

    std::array<int, static_cast<int>(       C0.cents())> arr0; // no surprise
    std::array<int, static_cast<int>(10_cents .cents())> arr1; // I'm surprised

even though operator""_cents() can throw (here's the implementation
for reference):

  inline constexpr currency operator""_cents(unsigned long long int cents)
  {
    constexpr auto mant_dig = std::numeric_limits<currency::data_type>::digits;
    constexpr unsigned long long int limit = 1ULL << mant_dig;
    return
          cents <= limit
        ? currency(static_cast<currency::data_type>(cents), raw_cents{})
        : throw std::runtime_error
            ("currency: " + std::to_string(cents) + " out of bounds");
        ;
  }

I would have reasoned that "10_cents" isn't *required* to be evaluated
at compile time because it's equivalent to a function call that can
throw (even though the called function is 'constexpr'):

  operator""_cents(10)

yet gcc-10 accepts it even if I write it with an explicit function call:

  std::array<int, static_cast<int>(operator""_cents(10).cents())> arr2;

Even though the compiler is *allowed* to accept that, is it *required* to?

But that academic question leads to a better, pragmatic one: shouldn't I
just tell the compiler what I really, really want, as follows?

- inline constexpr currency operator""_cents(unsigned long long int cents)
- inline consteval currency operator""_cents(unsigned long long int cents)
               ^^^ eval instead of expr

(Of course I'd have to change the corresponding friend declaration too, and
remove the unit test for run-time errors that become compile-time errors.)

Or should I wait until we're sure all compilers have implemented 'consteval'?


reply via email to

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