lmi
[Top][All Lists]
Advanced

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

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


From: Vadim Zeitlin
Subject: Re: [lmi] Why is this "=default" ctor needed?
Date: Wed, 20 Jan 2021 23:02:02 +0100

On Wed, 20 Jan 2021 21:50:13 +0000 Greg Chicares <gchicares@sbcglobal.net> 
wrote:

GC> Vadim--In branch valyuta/005, this succeeds:
GC> 
GC>   $make $coefficiency unit_tests unit_test_targets=currency_test
GC> 
GC> but it fails with this patch:
GC> 
GC> --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
GC> diff --git a/currency.hpp b/currency.hpp
GC> index 9c5558351..dcb11f59a 100644
GC> --- a/currency.hpp
GC> +++ b/currency.hpp
GC> @@ -75,8 +75,8 @@ class LMI_SO currency
GC>    public:
GC>      using data_type = double;
GC>  
GC> -//  currency() : m_ {0} {} // CURRENCY !! prevents "constexpr currency 
zero {};"
GC> -    currency() = default;
GC> +    currency() : m_ {0} {} // CURRENCY !! prevents "constexpr currency 
zero {};"
GC> +//  currency() = default;
GC>      explicit currency(data_type z, raw_cents) : m_ {z} 
{assert_integral(z);}
GC>  
GC>      currency& operator+=(currency const& z) {m_ += z.m_; return *this;}
GC> -->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8--

 Sorry, I don't understand the comment above, what does it mean?

GC> because:
GC> 
GC> In file included from /opt/lmi/src/lmi/currency_test.cpp:24:
GC> /opt/lmi/src/lmi/currency.hpp:159:27: error: the type ‘const currency’ of 
‘constexpr’ variable ‘C0’ is not literal
GC>   159 | inline constexpr currency C0 = {};
GC>       |                           ^~
GC> /opt/lmi/src/lmi/currency.hpp:61:14: note: ‘currency’ is not literal 
because:
GC>    61 | class LMI_SO currency
GC>       |              ^~~~~~~~
GC> /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
GC> 
GC> I'm surprised by that: I thought that patch would be just fine
GC> (even though I'd agree it's preferable to use "=default" to tell
GC> the compiler to do the work for me). Studying the gcc output:
GC>  - of course this isn't an 'aggregate':
GC>     - it has a nonstatic data member
GC>     - it has a user-declared ctor
GC>  - of course I wrote no 'constexpr' ctor

 But why? I.e. why not make this default ctor constexpr? I haven't tested
it yet, but this seems like the most natural way to solve the problem if
you absolutely need it at all. Of course, this assumes there is some reason
not to use "=default", even though right now I don't see any...

GC>  - I've always ignored "triviality"
GC> and "foo f = {}" has always seemed to work, so I figured there was
GC> nothing that I really needed to learn here--until now. Clearly the
GC> problem is that the patch destroys "triviality",

 No, I don't think so. You must use a constexpr expression to initialize a
constexpr variable and this expression is not constexpr any longer as it
involves a non-constexpr user-defined ctor.

GC> But I've provided a default ctor; why can't it be invoked?

 Because it's not constexpr.

GC> Can you tell me how these two default ctors differ:
GC>   currency() : m_ {0} {}
GC>   currency() = default;
GC> without using the words "literal" or "trivial"?

 The compiler-generated default ctor will be constexpr if possible, but the
user-defined one is explicitly not constexpr.

GC> If I replace "constexpr" with "static const", e.g.:
GC> 
GC> -inline constexpr currency C0 = {};
GC> +inline static const currency C0 = {};
GC> 
GC> then it seems to work just fine; but I'd rather have constexpr.

 Yes, of course.

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

 I think it's a pretty good guideline for many reasons and I do recommend
to always write this when there is no special reason to define the ctor
yourself.

GC> If that's the habit I need to adopt, then do I also actually need
GC>   ~foo() = default;
GC> and either
GC>   foo(foo const&) = default;
GC>   foo& operator=(foo const&) = default;

 Yes, all of those should IMO be written because they explicitly indicate
that this class has trivial (value-like) semantics and not just that its
copy ctor/dtor/etc were forgotten.

GC> or alternatively something postmodern like
GC>   foo(foo) = default;
GC>   foo& operator=(foo) = default;
GC> ?

 No, this wouldn't compile. But

      foo(foo&&) = default;
      foo& operator=(foo&&) = default;

would and would indeed be right and proper for a class with movable
semantics (e.g. std::unique_ptr), in which case you'd also write

      foo(foo const&) = delete;
      foo& operator=(foo const&) = delete;

 Regards,
VZ

Attachment: pgpSQ7Njzw7mG.pgp
Description: PGP signature


reply via email to

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