lmi
[Top][All Lists]
Advanced

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

[lmi] Why is this "=default" ctor needed?


From: Greg Chicares
Subject: [lmi] Why is this "=default" ctor needed?
Date: Wed, 20 Jan 2021 21:50:13 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.4.0

Vadim--In branch valyuta/005, this succeeds:

  $make $coefficiency unit_tests unit_test_targets=currency_test

but it fails with this patch:

--8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
diff --git a/currency.hpp b/currency.hpp
index 9c5558351..dcb11f59a 100644
--- a/currency.hpp
+++ b/currency.hpp
@@ -75,8 +75,8 @@ class LMI_SO currency
   public:
     using data_type = double;
 
-//  currency() : m_ {0} {} // CURRENCY !! prevents "constexpr currency zero 
{};"
-    currency() = default;
+    currency() : m_ {0} {} // CURRENCY !! prevents "constexpr currency zero 
{};"
+//  currency() = default;
     explicit currency(data_type z, raw_cents) : m_ {z} {assert_integral(z);}
 
     currency& operator+=(currency const& z) {m_ += z.m_; return *this;}
-->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8--

because:

In file included from /opt/lmi/src/lmi/currency_test.cpp:24:
/opt/lmi/src/lmi/currency.hpp:159:27: error: the type ‘const currency’ of 
‘constexpr’ variable ‘C0’ is not literal
  159 | inline constexpr currency C0 = {};
      |                           ^~
/opt/lmi/src/lmi/currency.hpp:61:14: note: ‘currency’ is not literal because:
   61 | class LMI_SO currency
      |              ^~~~~~~~
/opt/lmi/src/lmi/currency.hpp:61:14: note:   ‘currency’ is not an aggregate, 
does not have a trivial default constructor, and has no ‘constexpr’ constructor 
that is not a copy or move constructor

I'm surprised by that: I thought that patch would be just fine
(even though I'd agree it's preferable to use "=default" to tell
the compiler to do the work for me). Studying the gcc output:
 - of course this isn't an 'aggregate':
    - it has a nonstatic data member
    - it has a user-declared ctor
 - of course I wrote no 'constexpr' ctor
 - I've always ignored "triviality"
and "foo f = {}" has always seemed to work, so I figured there was
nothing that I really needed to learn here--until now. Clearly the
problem is that the patch destroys "triviality", but why should
that matter? Perhaps a better explanation is that a constexpr
variable requires a "literal" type; but that's apparently just a
type that allows constexpr, which seems to requires a trivial ctor.
I can figure out what the rule is, through a glass darkly, but...
why does such a rule exist?

AIUI, the empty braces in "C0 = {}" are parsed not as an empty
std::initializer_list, but as an invocation of a default ctor.
But I've provided a default ctor; why can't it be invoked?
Can you tell me how these two default ctors differ:
  currency() : m_ {0} {}
  currency() = default;
without using the words "literal" or "trivial"?

If I replace "constexpr" with "static const", e.g.:

-inline constexpr currency C0 = {};
+inline static const currency C0 = {};

then it seems to work just fine; but I'd rather have constexpr.

Is there a general guideline I'm supposed to take away from this,
like "always write 'foo() = default'"?

If that's the habit I need to adopt, then do I also actually need
  ~foo() = default;
and either
  foo(foo const&) = default;
  foo& operator=(foo const&) = default;
or alternatively something postmodern like
  foo(foo) = default;
  foo& operator=(foo) = default;
?



reply via email to

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