lmi
[Top][All Lists]
Advanced

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

Re: [lmi] depr.impldec


From: Greg Chicares
Subject: Re: [lmi] depr.impldec
Date: Thu, 28 Jul 2022 17:22:05 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.0

On 7/28/22 13:32, Vadim Zeitlin wrote:
> On Thu, 28 Jul 2022 09:53:07 +0000 Greg Chicares <gchicares@sbcglobal.net> 
> wrote:
> 
> GC> On 7/28/22 00:29, Vadim Zeitlin wrote:
> GC> > On Wed, 27 Jul 2022 19:55:32 +0000 Greg Chicares 
> <gchicares@sbcglobal.net> wrote:
> GC> > 
> GC> > GC> On 7/13/22 20:51, Greg Chicares wrote:
> GC> > GC> [...]
> GC> > GC> > I weakly favor the Rule of Zero, while you more strongly favor
> GC> > GC> > the Rule of Five, so let's start with a universal Rule of Five
> GC> > GC> 
> GC> > GC> I've changed my opinion.
> GC> [...]
> GC> >  One benefit that I hadn't mentioned yet, I think, is that if you ever
> GC> > define a special member in your class, e.g. decide to do something in 
> the
> GC> > default ctor, it would silently inhibit moving. This should, arguably,
> GC> > happen only rarely, but I guarantee that if it does happen, it will 
> remain
> GC> > unnoticed for a long time.
> GC> 
> GC> Unless we guarantee that it cannot happen, e.g., with "concept" 
> assertions.
> 
>  True, but this would require using concepts in all places where the class
> is used rather than defining the special member functions in a single
> place, so it's not clear if it provides a gain from the brevity point of
> view.

Really? Suppose I have:

  class X {...whatever...};
  
static_assert(lmi_is_effectively_moveable_and_copyable_and_at_least_semiregular);

I believe that the static_assert() (provided that it doesn't fire) guarantees
that X has the asserted properties everywhere and always, and that it's 
sufficient
to write the assertion OAOO, in the header, probably right after X's definition.
I believe these properties are all static, and ascertainable from X's definition
alone (along with the headers for the types of all data members).

Perhaps you're saying that headers like <concepts> or <type_traits>, and any
others we might create in, say, "concepts_lmi", are thereby included wherever
class X is used. But surely these headers will be manageably small, so their
widespread inclusion won't matter.

Or am I missing something enormous? I don't see how the asserted properties
could become invalid, no matter how the class is used.

> It still might be a better idea for other reasons though, e.g. it's
> arguably more important to know that the object passed to some function can
> be efficiently moved rather than knowing that objects of some class can be
> moved.

I'm striving to assert universal truths about classes, which become particular
truths about objects of those classes, yet still remain truthful.

> GC> >  Also, there are many important exceptions, e.g. you still have to write
> GC> > all 5 special members for any polymorphic base classes
> GC> 
> GC> But we can write them all once...
> GC> 
> GC>   #include "crtp_base.hpp"
> GC> 
> GC> ...and only once:
> GC> 
> GC>   class A : private lmi::polymorphic_base<A> {};
> GC>   static_assert( std::is_polymorphic_v           <A>);
> GC>   static_assert( std::is_default_constructible_v <A>);
> GC>   static_assert( std::is_destructible_v          <A>);
> GC>   static_assert( std::is_copy_constructible_v    <A>);
> GC>   static_assert( std::is_move_constructible_v    <A>);
> GC>   static_assert( std::is_copy_assignable_v       <A>);
> GC>   static_assert( std::is_move_assignable_v       <A>);
> GC> 
> GC> (and those assertions can be combined into one "concept").
> 
>  Just to be sure, did you really mean write all these asserts positively
> like this or was it a typo?

That was cut and pasted from a (locally modified) copy of a unit test,
which passes: none of those assertions fires. I think you could copy
and paste it into 'crtp_base_test.cpp' and build it successfully
(but I hope to push it soon enough).

> Because I'd expect polymorphic types _not_ to
> be copyable nor movable.

Class A above is both. And it remains so if we add, say:
  int a_member_ {0};
to it. And
  class B : protected A {};
has (implicit) move and copy operations that do the right thing.
If we add
  std::ostream& os_;
then it loses some of those properties, but maybe we don't need
to add such a member. If we add only data members that don't
spoil those properties, and static_assert every property at the
end of the class definition, then we're in a Rule-of-Zero state
of grace, and we can still write a great deal of useful code.

This command:
  git grep "Implicitly-declared special member functions do the right thing."
finds thirty-one matches. Supposing that the comment is actually
true wherever written, we can replace it with a static assertion
that cannot fire, and those thirty-one classes enter this state
of grace: they're both movable and copyable, and achieve the
full move-semantics efficiency that is the most important part
of modern C++.

I think you're saying that we live in a fallen world where others
have written code that cannot be Rule-of-Zeroed yet remain both
movable and copyable. Maybe I can show them a path to that
promised land, so they never have to write another move or copy
ctor. Or maybe it's not as good an idea as I dream it might be:
  https://wiki.c2.com/?TheyLaughedAtEinstein
Still, I want to find out how far I can take it, with lmi at least.


reply via email to

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