[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'?
- [lmi] Should lmi use 'consteval' yet?,
Greg Chicares <=