Topic: auto generated (default) constructora and copy operators


Author: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 7 Jul 2006 01:24:15 GMT
Raw View
manfred@techniroot.co.za (Manfred von Willich) wrote (abridged):
> the difference in the number of keystrokes between writing "auto"
> (or maybe "{ default; }") and "{ return !(*this==B); }" is minimal
> (the definition of == coincides between the two suggestions).  I do
> not call that significantly useful.

I see that as an argument disallowing auto for !=. I don't see it as an
argument for defining auto != in terms of memberwise !=. Nor for
disallowing auto for ==, where it could save a lot of code.

And in my view, if auto is supported for ==, then there would need to be a
good reason /not/ to support it for !=. The advantage is a more uniform
scheme, rather than saved keystrokes.

In addition, I think that:
    { default }

is significantly clearer than either of:
    { return !(*this==rhs); }
    { return !operator==(rhs); }

because the latter have to be checked more carefully. Somebody might
write:
   { return !*this==rhs; }

by mistake.


> > The main problem is that == and != may be defined in different
> > translation units, so the compiler can't look at == when deciding
> > how to implement != and vice versa.
>
> I'm afraid I must be missing something here.

I was agreeing with your point that:

    to suggest that the default version must be defined in
    terms of the other (if it is explicitly defined)

leads to problems. I understood the context to be a suggested rule like:

   If != is hand-written, then auto == is defined in terms of it.
   Otherwise, auto == is defined in terms of memberwise ==.

We're agreed that this won't fly.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Fri, 7 Jul 2006 12:59:57 GMT
Raw View
In article <1152201890.829727.41010@75g2000cwc.googlegroups.com>,
Manfred von Willich <manfred@techniroot.co.za> writes
>I'm getting a little confused here.  If the equality and inequality
>operators were compiler-generated without a request, we would save the
>need to declare one or both.  However, since we are talking about where
>the auto/default versions must be explicitly requested, the difference
>in the number of keystrokes between writing "auto" (or maybe "{
>default; }") and "{ return !(*this==B); }" is minimal (the definition
>of == coincides between the two suggestions).  I do not call that
>significantly useful.


There is a potential documentary advantage to writing something like :

bool operator==(mytype const &) = default;

it tells the reader that there should be no surprises. It also reduces
the potential for typos.

Note that I am not yet advocating adding this to the Standard, just that
once we have settled on an explicit syntax to deal with compiler
generated implementation we can, if we choose to, extend it to other
member functions. I think we might make a good case for making swap()
one of those.

However my main concern is to reduce the incidence of implicit function
declaration and definition, which is my motivation for the 'explicit
class' proposal.

--
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@acm.org (James Dennett)
Date: Fri, 7 Jul 2006 14:17:29 GMT
Raw View
Manfred von Willich wrote:
> Dave Harris wrote:
>> Yes. But why would anyone do that? It's no better logically, and if the
>> default operator is inline there shouldn't be any performance difference.
>> There is no existing code that specifies default for == either. It doesn't
>> seem to be worth worrying about.
>>
>> With your approach, if I want to define one of == and != I have to define
>> both. With my approach, I can get away with defining just one of them so
>> long as it is ==. So mine is a net win. It's more useful.
>>
>> I do see this as being more about usefulness than correctness. Sometimes
>> the default definitions will be wrong, and then it will be a mistake to
>> request them, but I see that as the programmer's fault rather than the
>> language's. It's no different to writing the wrong definition out by hand.
>> The programmer remains responsible for doing the right thing - you can't
>> avoid that.
>>
> I'm getting a little confused here.  If the equality and inequality
> operators were compiler-generated without a request, we would save the
> need to declare one or both.  However, since we are talking about where
> the auto/default versions must be explicitly requested, the difference
> in the number of keystrokes between writing "auto" (or maybe "{
> default; }") and "{ return !(*this==B); }" is minimal (the definition
> of == coincides between the two suggestions).  I do not call that
> significantly useful.

Others of us do.  A default version would unavoidably follow
the language rules, and doesn't need to be checked at all; a
user-defined one can contain implementation errors, or might
do something slightly non-standard.  A small but worthwhile
gain.

[snip]

> James Dennett wrote:
>> Manfred von Willich wrote:
>>> If the rule is as you suggested it, that
>>> <snip>
>>> then if we write
>>>     bool operator==(thisclass const & B) auto;
>>>     bool operator!=(thisclass const & B) const { return nonsense(); }
>>> then the operators == and != may be inconsistent.
>> Not very relevant, in my estimation: it doesn't make
>> it impossible to be inconsistent, but it does mean
>> that natural code will be consistent.
>>
>>> Ergo, your suggestion does not necessarily avoid inconsistency between
>>> == and !=, in apparently reasonable code.
>> The code you show above is unreasonable, in my book.
>> I've never had cause to implement operator!= as
>> anything other than the negation of ==.
>>
>>> The benefit of being able to
>>> say
>>>     bool operator!=(thisclass const &) const auto;
>>> instead of
>>>     bool operator!=(thisclass const & B) const { return !operator==(B);
>>> }
>>> is rather doubtful, especially since the latter is more immediately
>>> obvious.
>> We can disagree there.
>>
> See my response to Dave above.  I presume that here you are referring
> to what is more immediately obvious, not the value of the benefit,
> which as I say is minimal.

I'm speaking of the value of the benefit, which I describe
as worthwhile.

>>> C++ does not even pretend to encourage operator consistency - it lets
>>> us hijack operators for unrelated uses (e.g. cout::operator<<).
>> C++ does encourage consistency, it just doesn't enforce
>> it at a language level (though the library requires a
>> certain level of consistency).
>>
>
> How so?  At language level I think that aside from the
> compiler-generated methods and the existing consistency with predefined
> types, the apparently related operators are entirely unrelated.  Be
> careful that you don't read your bias into the language.

Please don't presume that I'm reading something into "the
language".  Instead, let's differentiate between the concrete
rules codified in the C++ standard from "C++", which is more
than just what is formalized.

You've noted already that all of the supplied implementations
of == and != satisfy the obvious relationship, and you would,
I hope, agree that the C++ community generally frowns upon
overloading operators for other than their traditional
purposes.  (IOStreams *was* an exception to that -- but in
modern C++, << and >> are most often used as insertion and
extraction operators rather than bit-shifts.)

The names of the == and != operators as given by the C++
standard are "equal to" and "not equal to".  That strongly
suggests that they are expected to have this relationship.

Claiming that these are "entirely unrelated" at the language
level seems to depend on some definitions that differ from
mine, or from those of the standard.

-- James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Sat, 8 Jul 2006 20:33:49 CST
Raw View
I am deliberately editing what was a long response of mine to keep it
short.

I agree eventually - with all three of you - that == (and many other
operators potentially including !=) as having a default is potentially
very useful, and that choice of the actual definition could be weighted
heavily by what is intuitively correct and consistent, and at this
stage I will not try to argue for or against any particular version.
And I very much like the "explicit class" proposal.  I still disagree
with James about what the standard (not C++ at large) says about the
interpretation of == and !=, but I do not think this is important at
this stage.

I think it important to explore broader conceptual frameworks before
settling on one or two of the default operator definitions.  I'll start
by throwing in some assertions, but please feel free to shred them and
put something else in their place.

*  Whatever definition is specified for a default method or operator,
the "no surprises" principle must apply.

*  Should the consistency become a goal in the standard?  Consistency
should be investigated in the following sets and more, and a policy
determined in relation to consistency:
   =, +=, + (ditto all assigment operators)
   =, standard-ctor, copy-ctor, and corresponding methods of members
   ==, !=, !
   <=, >, !
   >=, <, !
   &&, ||, !
Is it possible to get the compiler to verify a contract of consistency?

*  There seems to be a first-pass "obvious" definition for ==: generate
the &&-conjoined expression of == applied memberwise to the class, in
the same order as construction, provided == is defined for each member.

*  We have a candidate for !=, which is !operator==.

*  There is obvious no candidate for inequality operators, though there
are obvious ways to derive the rest from any one of them and ==.

*  When there is potential ambiguity (inconsistency), I think there
should be no default definition until more exploration has been done.
This will encourage code that allows the compiler to verify consistency
(e.g. via =default in class declarations).

*  Padding fields should be handled as being extraneous.  For
comparision, either the padding must be known and always the same
between objects of the same class, or it must be masked out of the
comparison.

*  "friend" defaults must be considered.  "friend bool operator==(cl
const &, cl const &) = default;" will typically be more useful than
"bool operator==(cl const &) const = default;".

*  Whenever the relevant operators (e.g. == and && used in the
definition of the default ==) return something other than a bool
(tribool is a good example), these types should get used as-is (e.g.
tribool), with normal implicit conversion where appropriate.

*  A reference member implies acting on (e.g. comparing) the referenced
object.

*  A pointer member should be treated with caution.  The shallow/deep
problem occurs here, neither being "obviously" best.  I would prefer to
see the default suppressed.

*  Look at permitting defaults being defined in terms of each other.
Sometimes we want to define += in terms of +, and sometimes the other
way around - for efficiency in either case.

*  Should we relook the =default cases in an explicit class w.r.t. the
constructors and assignment operator?  In particular, if assigment has
been explicitly defined for a class, it is probably more consistent to
define the copy ctor in terms of the default ctor ands assignment.

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: musiphil@bawi.org (Seungbeom Kim)
Date: Sun, 9 Jul 2006 19:15:10 GMT
Raw View
Seungbeom Kim wrote:
>> On Thu, 29 Jun 2006 16:13:41 CST, "Andrei Polushin"
>> <polushin@gmail.com> wrote:
>>
>>> What about "explicit class"?
>>>
>>>  explicit class Whatever {
>>>    // has no compiler-generated members unless you declare them
>>>  };
>
> It makes the explicit class look like a different kind of class,
> doesn't it? Whether a class has certain compiler-generated member
> function or not - I don't find it that important a property to be
> entitled to qualify the entire class definition.

I'd like to hear what others think about the point mentioned above,
but have seen many people liking the "explicit class" idea without
specifically mentioning the point. I'm not sure whether they disagree
to the point above or just need something, of which "explicit class"
has been the most popular.

> Instead, a better way would be to turn off generation of each
> compiler-generated members, individually. Along the lines of the
> proposed syntax in my previous posting, we could adopt something like:
>
>     class Whatever // non-copyable
>     {
>     public:
>         // ...
>         Whatever(const Whatever&) != default;
>         Whatever& operator=(const Whatever&) != default;
>         // The default constructor and the destructor are
>         // still automatically generated by the compiler.
>     };

Though it may not have been stated very explicitly, this syntax has the
advantage of allowing making a class non-copyable (via copy construction
or assignment) while leaving it still default-constructible. Of course,
it makes quite clear which member functions are suppressed; with the
class definition just marked "explicit", I cannot see exactly which
member functions are suppressed, specifically whether the destructor is
there or not. (On one hand the rule would be simpler if all of the four
compiler-generated member functions are disabled for "explicit" classes,
but on the other hand I don't see the need to disable the destructor
very often and it would restrict the usefulness of "explicit" classes.)

I do not insist on the particular syntax proposed above (even though I
like it), but I do believe that suppressing the compiler-generated
members should be member-wise, not class-wise. (Of course, I'm open to
persuasion and my opinion may change later.)

> Regarding the keyword explicit, I regret having it as it is now;
> the rules are very inconsistent. If a constructor requires two or more
> arguments, it is inherently explicit; if a constructor can be called
> with only one argument, it is non-explicit (or 'implicit') by default,
> and should be explicitly marked 'explicit'. Suppose you have a
> constructor which required two arguments, whose explicitness you have
> relied on, and later you supply a default to the second argument, then
> you suddenly make it non-explicit without noticing it.
>
> What we should have done is to make all constructors explicit by
> default, and let the keyword 'implicit' (or whatever) selectively mark
> those which aren't supposed to be explicit. Of course it's too late for
> any change like this, I know. :(

Another (small) reason why I don't like the "explicit" class idea is
that the keyword "explicit" has been a mistake, as stated above. Of
course we can reuse a keyword for something useful, even though the
keyword began its life as a mistake, but I don't like to see the
already-mistaken idea spread and grow with another usage of the keyword.

--
Seungbeom Kim

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Mon, 10 Jul 2006 13:31:22 GMT
Raw View
musiphil@bawi.org (Seungbeom Kim) wrote (abridged):
> Instead, a better way would be to turn off generation of each
> compiler-generated members, individually. Along the lines of the
> proposed syntax in my previous posting, we could adopt something like:
>
>     class Whatever // non-copyable
>     {
>     public:
>         // ...
>         Whatever(const Whatever&) != default;
>         Whatever& operator=(const Whatever&) != default;
>         // The default constructor and the destructor are
>         // still automatically generated by the compiler.
>     };

To me this doesn't seem very different to declaring them normally but
making them private and not giving them an implementation. (With my local
compiler, member functions that are not used don't have to defined, and if
they are not defined but get used anyway I get a linker error.)

Also, it is a lot of code, and it requires the programmer to know which
members are generated by default. It seems like a feature that only
experts will use. If that.


> It makes the explicit class look like a different kind of class,
> doesn't it?

A bit, yes. Maybe it should come later in the syntax.

    class explicit Derived : public Base {

    class Derived explicit : public Base {

    class Derived : explicit, public Base {

The last of these offers the cute conceit that the default members are
inherited, which I think is far too muddled to use. The middle one I think
gets across the idea that the "explicit" is a class-wide modifier without
implying more than that. It would make sense to me to put more modifiers
in there, eg "pod" or "final" or "abstract", if we wanted such language
extensions in the future.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Mon, 10 Jul 2006 10:43:32 CST
Raw View
Seungbeom Kim wrote:
> Seungbeom Kim wrote:
> >> On Thu, 29 Jun 2006 16:13:41 CST, "Andrei Polushin"
> >> <polushin@gmail.com> wrote:
> >>
> >>> What about "explicit class"?
> >>>
> >>>  explicit class Whatever {
> >>>    // has no compiler-generated members unless you declare them
> >>>  };
> >
> > It makes the explicit class look like a different kind of class,
> > doesn't it? Whether a class has certain compiler-generated member
> > function or not - I don't find it that important a property to be
> > entitled to qualify the entire class definition.
>
> I'd like to hear what others think about the point mentioned above,
> but have seen many people liking the "explicit class" idea without
> specifically mentioning the point. I'm not sure whether they disagree
> to the point above or just need something, of which "explicit class"
> has been the most popular.
>
> > Instead, a better way would be to turn off generation of each
> > compiler-generated members, individually. Along the lines of the
> > proposed syntax in my previous posting, we could adopt something like:
> >
> >     class Whatever // non-copyable
> >     {
> >     public:
> >         // ...
> >         Whatever(const Whatever&) != default;
> >         Whatever& operator=(const Whatever&) != default;
> >         // The default constructor and the destructor are
> >         // still automatically generated by the compiler.
> >     };
>
> Though it may not have been stated very explicitly, this syntax has the
> advantage of allowing making a class non-copyable (via copy construction
> or assignment) while leaving it still default-constructible. Of course,
> it makes quite clear which member functions are suppressed; with the
> class definition just marked "explicit", I cannot see exactly which
> member functions are suppressed, specifically whether the destructor is
> there or not. (On one hand the rule would be simpler if all of the four
> compiler-generated member functions are disabled for "explicit" classes,
> but on the other hand I don't see the need to disable the destructor
> very often and it would restrict the usefulness of "explicit" classes.)
>
> I do not insist on the particular syntax proposed above (even though I
> like it), but I do believe that suppressing the compiler-generated
> members should be member-wise, not class-wise. (Of course, I'm open to
> persuasion and my opinion may change later.)
>
> > Regarding the keyword explicit, I regret having it as it is now;
> > the rules are very inconsistent. If a constructor requires two or more
> > arguments, it is inherently explicit; if a constructor can be called
> > with only one argument, it is non-explicit (or 'implicit') by default,
> > and should be explicitly marked 'explicit'. Suppose you have a
> > constructor which required two arguments, whose explicitness you have
> > relied on, and later you supply a default to the second argument, then
> > you suddenly make it non-explicit without noticing it.
> >
> > What we should have done is to make all constructors explicit by
> > default, and let the keyword 'implicit' (or whatever) selectively mark
> > those which aren't supposed to be explicit. Of course it's too late for
> > any change like this, I know. :(
>
> Another (small) reason why I don't like the "explicit" class idea is
> that the keyword "explicit" has been a mistake, as stated above. Of
> course we can reuse a keyword for something useful, even though the
> keyword began its life as a mistake, but I don't like to see the
> already-mistaken idea spread and grow with another usage of the keyword.
>
> --
> Seungbeom Kim


I, for one, am strongly in favour of turning off all the
compiler-generated member functions simultaneously, and then
re-enabling them individually - not switching them off individually.
This forms part of a more general principle that IMHO should have been
adopted by this forum a long time ago, namely that semantics should be
kept as orthogonal and direct as possible w.r.t. syntax.  The idea of
having implied unstated methods means that for any class we have the
following: The available member functions are those that have been
declared, plus default ctor, copy ctor, copy-assignment and the dtor,
provided of course generation thereof was not suppressed (silently) due
to any of a number of conditions, too complicated to enumerate here.
The ("explicit class") alternative, each method is part of the class if
and only if it is declared.

On the matter of the aesthetics of the syntax "explicit class", I do
not like it either, but failing better suggestion, I find it far
preferable to selectively suppressing member functions.  I consider
this to be merely a challenge of how to syntactically distinguish the
"cleaner" interface.  Perhaps class [ ... ] instead of class { ... } ?

Another violation of the general rule I have suggested here (and should
perhaps be tied in with this change) is that PODness is determined by a
complex series of rules.  I would far rather have PODness determined by
the programmer, and the compiler applying the rules to see whether the
programmer's choice can be satisfied.  So, for example, class [ ... ]
could be always non-POD, and struct [ ... ] always POD (and I would
like to see union left out of this change entirely - left in its
original form until a cleaner approach can be adopted, maybe using
"case" inside "struct [ ... ]").

As to your "advantage" of being able to choose contructable, copyable,
copy-assignable and destructable qualities, you have exactly the same
with the "explicit class", only more intuitively expressed (at least to
an inexperienced programmer): It is exactly what it is declared as,
rather than being whatever the programmer (explicitly, using
"!=default" or other declaration) and the compiler (following involved
rules) have not crossed off from the list of four methods plus
declarations.

The case of the destructor may be a little less obvious, but I still
have a strong stance on it (it should not exist unless defined).  The
need to qualify the destructor occurs often enough that the advantage
of not having to declare it is not as significant as might be thought.
If the destructor is to be non-public or virtual, it still has to be
declared - besides, public non-virtual destructors belong only in a
specialised category of classes (non-derived, non-base classes, or
where derivation adds no data members).  It is clearer to declare
exactly which destructor you want (typically using "=default").  No
destructor declared?  There is none (atypical as this might be).
Declared private?  There is a private destructor.  Instead of:  No
destructor declared?  There may be a public destructor, providing other
rules are satisfied.  Declared private?  The intent may be to either
have a private destructor, or else to have none (in which case
non-definition and the linker will be relied upon to ensure this).

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Mon, 10 Jul 2006 18:30:57 GMT
Raw View
manfred@techniroot.co.za (Manfred von Willich) wrote (abridged):
> I'll start by throwing in some assertions, but please feel free to
> shred them and put something else in their place.

They mostly look reasonable to me.


> *  Should the consistency become a goal in the standard?
> [...]
> Is it possible to get the compiler to verify a contract of consistency?

I don't think that's appropriate for C++ at this stage. In general, to
check whether two functions have the same run-time semantics involves
solving the Halting Problem, which is impossible, and I don't think it's
right for C++ to restrict the general case to ones which can be solved.

Encouraging and supporting consistency is another matter. Consistency
should be a goal of default operator definitions. And of course
implementations can issue warnings about inconsistent definitions that
they detect.


> *  We have a candidate for !=, which is !operator==.

I agree that one is clearly best, but there are two others that I can see.
The first is memberwise != combined with ||, as suggested earlier. The
other is as !(lhs < rhs) && !(rhs < lhs), which gives the usually expected
relationship with inequality operators.


> *  There is obvious no candidate for inequality operators,

Well, operator<() can be defined by the lexical ordering of the members.

    if (lhs.member0 < rhs.member0)
        return true;
    if (rhs.member0 < lhs.member0)
        return true;
    // Repeat the above for all members
    return false; // lhs and rhs are equal.

We can argue about whether it should be done entirely in terms of
operator<() as above, or whether operator==() should be used as well:

    if (!(lhs.member0 == rhs.member0))
        return lhs.member0 < rhs.member0;
    // Repeat the above for all members
    return false; // lhs and rhs are equal.

Personally I prefer this because == is notionally "cheaper" then <, but I
wouldn't veto a proposal that chose the other one.

Using memberwise less_than() is arguably better than using operator<() as
it works for pointers.

I think default< is worth considering because, judging from occasional
posts to these forums, inexperienced programmers often struggle to get it
right. It is probably the most code, too - the most bang per buck.


> though there are obvious ways to derive the rest from any one of them
> and ==.

You don't need ==.
    lhs < rhs   as above.
    lhs > rhs   rhs < lhs
    lhs <= rhs  !(rhs < lhs)
    lhs >= rhs  !(lhs < rhs)

As with operator!=(), I am happy to pick one relation arbitrarily (in this
case operator<()) and define the others in terms of it. I am not bothered
by the asymmetry.

These are fiddly to get right so worth adding on that score. However, if
we have to write out all the declarations by hand it will still be a lot
of code. I wonder whether we need a way of generating a lot of operators
at once. Without that, the boost solution is arguably better.


> *  A pointer member should be treated with caution.  The shallow/deep
> problem occurs here, neither being "obviously" best.  I would prefer to
> see the default suppressed.

Too late. For operator=(), the default is already shallow. Given that
these operators must be requested by default, I think the onus should be
on the programmer to only request them when they have the right semantics,
rather than the standard to second-guess whether the programmer is
mistaken.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Mon, 3 Jul 2006 17:25:17 GMT
Raw View
manfred@techniroot.co.za (Manfred von Willich) wrote (abridged):
>    bool operator== (Whatever const &) const;
>    bool operator!= (Whatever const &) const;
> Like the assignment and copy constructors, these can be unambiguously
> defined in terms of the like operators of the base objects and member
> objects (using && and ||) - using the same order as for construction,
> including short-circuit evaluation.

I would prefer operator!=() to be defined in terms of operator==(). For
example:

    struct MyClass {
        MyData *p;
    };

    bool operator==( const MyClass &a, const MyClass &b ) {
        return *a.p == *b.p;
    }

    bool operator!=( const MyClass &a, const MyClass &b ) = default;

If I understand you correctly, the last line would generate:

    bool operator!=( const MyClass &a, const MyClass &b ) {
        return a.p != b.p;
    }

which is wrong here (it misses a dereference). I'd rather:

    bool operator!=( const MyClass &a, const MyClass &b ) {
        return !(a == b);
    }

to guarantee that == and != match. I can't think of any situation where I
wouldn't prefer this.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Tue, 4 Jul 2006 16:51:22 CST
Raw View
Francis Glassborow wrote:
> In article <1151766207.224845.246440@b68g2000cwa.googlegroups.com>,
> Manfred von Willich <manfred@techniroot.co.za> writes
> >Would there be value in allowing the two following "explicitly default"
> >member functions, since IMHO they can be conveniently and safely added?
> > These are
> >   bool operator== (Whatever const &) const;
> >   bool operator!= (Whatever const &) const;
> >Like the assignment and copy constructors, these can be unambiguously
> >defined in terms of the like operators of the base objects and member
> >objects (using && and ||) - using the same order as for construction,
> >including short-circuit evaluation.  (I also suggested this in a
> >another thread in this group).  If the necessary operators no not
> >exist, then the "default" version cannot be generated, as with copy
> >etc.
> The authors of 1717 (i.e. me and Lois Goldthwaite) are taking a
> conservative line. We know that there are other candidates for our
> 'default' proposal but we would prefer that those be provided, in the
> first instance, as extensions by compiler implementors until we are
> certain that there are no unforeseen problems.

With further thought, I think that this conservative approach is wise:
   (a) There are different ways in which the standard could lean in
terms of defining the "default" version, none of them obviously better
than others, and mandating one would be closing the door on other
approaches.
   (b) Not bringing in this suggestion with n1717 does not close any
doors on its future adoption.
   (c) I am not aware that the lack of these operators is a general
achilles heel (as in often finding that we wished it were there).

If my suggestion is considered at all, I think it should initially be
limited to the "unambiguous" cases, e.g. PODs without a user-defined ==
or != for any member (thus hopefully yielding the equivalent of
memcmp).  However, even here I am having my doubts, since treatment of
"ignore" fields (e.g. padding) must be considered.


Dave Harris wrote:
> I would prefer operator!=() to be defined in terms of operator==(). For
> example:
>
>     struct MyClass {
>         MyData *p;
>     };
>
>     bool operator==( const MyClass &a, const MyClass &b ) {
>         return *a.p == *b.p;
>     }
>
>     bool operator!=( const MyClass &a, const MyClass &b ) = default;
>
> If I understand you correctly, the last line would generate:
>
>     bool operator!=( const MyClass &a, const MyClass &b ) {
>         return a.p != b.p;
>     }
>
> which is wrong here (it misses a dereference). I'd rather:
>
>     bool operator!=( const MyClass &a, const MyClass &b ) {
>         return !(a == b);
>     }
>
> to guarantee that == and != match. I can't think of any situation where I
> wouldn't prefer this.

You understand correctly.  Your approach does not guarantee what you
think it does: With it, if you define != instead and specify default
behaviour for ==, you end up with the same problem as with my approach
- and to suggest that the default version must be defined in terms of
the other (if it is explicitly defined) leads to other ambiguities,
such as when neither is explicitly defined.

It is becoming clear that this is a more complex issue than I had
anticipated, largely due to the way in which C++ allows/requires
independent specification of closely related operators.  Accordingly, I
would recommend that some mechanism of ensuring semantic conformance of
related operators should be tackled before this suggestion is taken
further.

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@acm.org (James Dennett)
Date: Tue, 4 Jul 2006 23:26:43 GMT
Raw View
Manfred von Willich wrote:
> Dave Harris wrote:
>> I would prefer operator!=() to be defined in terms of operator==(). For
>> example:
>>
>>     struct MyClass {
>>         MyData *p;
>>     };
>>
>>     bool operator==( const MyClass &a, const MyClass &b ) {
>>         return *a.p == *b.p;
>>     }
>>
>>     bool operator!=( const MyClass &a, const MyClass &b ) = default;
>>
>> If I understand you correctly, the last line would generate:
>>
>>     bool operator!=( const MyClass &a, const MyClass &b ) {
>>         return a.p != b.p;
>>     }
>>
>> which is wrong here (it misses a dereference). I'd rather:
>>
>>     bool operator!=( const MyClass &a, const MyClass &b ) {
>>         return !(a == b);
>>     }
>>
>> to guarantee that == and != match. I can't think of any situation where I
>> wouldn't prefer this.
>
> You understand correctly.  Your approach does not guarantee what you
> think it does: With it, if you define != instead and specify default
> behaviour for ==, you end up with the same problem as with my approach
> - and to suggest that the default version must be defined in terms of
> the other (if it is explicitly defined) leads to other ambiguities,
> such as when neither is explicitly defined.

I must be missing something: I see that the suggested
approach does avoid the problem in question, which is
inconsistent behavior of == and !=, by defining != in
terms of ==, and == in terms of memberwise ==.

Naturally this doesn't address any pre-existing problems
of members whose only == and != operators are in conflict
but that's not something that can be fixed by a class
that contains them.

So, I'm wondering what problem you're talking about
with defining != and == this way (when requested).

-- James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 6 Jul 2006 01:30:16 GMT
Raw View
manfred@techniroot.co.za (Manfred von Willich) wrote (abridged):
> You understand correctly.  Your approach does not guarantee what you
> think it does:

I should have qualified "guarantee" a bit more :-)


> With it, if you define != instead and specify default behaviour for
> ==, you end up with the same problem as with my approach

Yes. But why would anyone do that? It's no better logically, and if the
default operator is inline there shouldn't be any performance difference.
There is no existing code that specifies default for == either. It doesn't
seem to be worth worrying about.

With your approach, if I want to define one of == and != I have to define
both. With my approach, I can get away with defining just one of them so
long as it is ==. So mine is a net win. It's more useful.

I do see this as being more about usefulness than correctness. Sometimes
the default definitions will be wrong, and then it will be a mistake to
request them, but I see that as the programmer's fault rather than the
language's. It's no different to writing the wrong definition out by hand.
The programmer remains responsible for doing the right thing - you can't
avoid that.


> - and to suggest that the default version must be defined in terms of
> the other (if it is explicitly defined) leads to other ambiguities,
> such as when neither is explicitly defined.

The main problem is that == and != may be defined in different translation
units, so the compiler can't look at == when deciding how to implement !=
and vice versa.

If it weren't for that, I'd be happy to say that default == is only
permitted when != is also default. But it doesn't really matter, and in
practice implementations will usually be able to detect the situation and
issue a warning.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Wed, 5 Jul 2006 20:32:45 CST
Raw View
James Dennett wrote:
> Manfred von Willich wrote:
> > You understand correctly.  Your approach does not guarantee what you
> > think it does: With it, if you define != instead and specify default
> > behaviour for ==, you end up with the same problem as with my approach
> > - and to suggest that the default version must be defined in terms of
> > the other (if it is explicitly defined) leads to other ambiguities,
> > such as when neither is explicitly defined.
>
> I must be missing something: I see that the suggested
> approach does avoid the problem in question, which is
> inconsistent behavior of == and !=, by defining != in
> terms of ==, and == in terms of memberwise ==.
>
> Naturally this doesn't address any pre-existing problems
> of members whose only == and != operators are in conflict
> but that's not something that can be fixed by a class
> that contains them.
>
> So, I'm wondering what problem you're talking about
> with defining != and == this way (when requested).

If the rule is as you suggested it, that
    bool operator==(thisclass const &) const auto;
is defined by memberwise ==, and
    bool operator!=(thisclass const &) const auto;
is defined as
    bool operator!=(thisclass const & B) const { return !operator==(B);
}
then if we write
    bool operator==(thisclass const & B) auto;
    bool operator!=(thisclass const & B) const { return nonsense(); }
then the operators == and != may be inconsistent.

Ergo, your suggestion does not necessarily avoid inconsistency between
== and !=, in apparently reasonable code.  The benefit of being able to
say
    bool operator!=(thisclass const &) const auto;
instead of
    bool operator!=(thisclass const & B) const { return !operator==(B);
}
is rather doubtful, especially since the latter is more immediately
obvious.

C++ does not even pretend to encourage operator consistency - it lets
us hijack operators for unrelated uses (e.g. cout::operator<<).

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: James Dennett <jdennett@acm.org>
Date: Thu, 6 Jul 2006 00:15:15 CST
Raw View
Manfred von Willich wrote:
> James Dennett wrote:
>> Manfred von Willich wrote:
>>> You understand correctly.  Your approach does not guarantee what you
>>> think it does: With it, if you define != instead and specify default
>>> behaviour for ==, you end up with the same problem as with my approach
>>> - and to suggest that the default version must be defined in terms of
>>> the other (if it is explicitly defined) leads to other ambiguities,
>>> such as when neither is explicitly defined.
>> I must be missing something: I see that the suggested
>> approach does avoid the problem in question, which is
>> inconsistent behavior of == and !=, by defining != in
>> terms of ==, and == in terms of memberwise ==.
>>
>> Naturally this doesn't address any pre-existing problems
>> of members whose only == and != operators are in conflict
>> but that's not something that can be fixed by a class
>> that contains them.
>>
>> So, I'm wondering what problem you're talking about
>> with defining != and == this way (when requested).
>
> If the rule is as you suggested it, that
>     bool operator==(thisclass const &) const auto;
> is defined by memberwise ==, and
>     bool operator!=(thisclass const &) const auto;
> is defined as
>     bool operator!=(thisclass const & B) const { return !operator==(B);
> }
> then if we write
>     bool operator==(thisclass const & B) auto;
>     bool operator!=(thisclass const & B) const { return nonsense(); }
> then the operators == and != may be inconsistent.

Not very relevant, in my estimation: it doesn't make
it impossible to be inconsistent, but it does mean
that natural code will be consistent.

> Ergo, your suggestion does not necessarily avoid inconsistency between
> == and !=, in apparently reasonable code.

The code you show above is unreasonable, in my book.
I've never had cause to implement operator!= as
anything other than the negation of ==.

> The benefit of being able to
> say
>     bool operator!=(thisclass const &) const auto;
> instead of
>     bool operator!=(thisclass const & B) const { return !operator==(B);
> }
> is rather doubtful, especially since the latter is more immediately
> obvious.

We can disagree there.

> C++ does not even pretend to encourage operator consistency - it lets
> us hijack operators for unrelated uses (e.g. cout::operator<<).

C++ does encourage consistency, it just doesn't enforce
it at a language level (though the library requires a
certain level of consistency).

-- James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Thu, 6 Jul 2006 13:21:02 CST
Raw View
Dave Harris wrote:
>
> Yes. But why would anyone do that? It's no better logically, and if the
> default operator is inline there shouldn't be any performance difference.
> There is no existing code that specifies default for == either. It doesn't
> seem to be worth worrying about.
>
> With your approach, if I want to define one of == and != I have to define
> both. With my approach, I can get away with defining just one of them so
> long as it is ==. So mine is a net win. It's more useful.
>
> I do see this as being more about usefulness than correctness. Sometimes
> the default definitions will be wrong, and then it will be a mistake to
> request them, but I see that as the programmer's fault rather than the
> language's. It's no different to writing the wrong definition out by hand.
> The programmer remains responsible for doing the right thing - you can't
> avoid that.
>
I'm getting a little confused here.  If the equality and inequality
operators were compiler-generated without a request, we would save the
need to declare one or both.  However, since we are talking about where
the auto/default versions must be explicitly requested, the difference
in the number of keystrokes between writing "auto" (or maybe "{
default; }") and "{ return !(*this==B); }" is minimal (the definition
of == coincides between the two suggestions).  I do not call that
significantly useful.

> The main problem is that == and != may be defined in different translation
> units, so the compiler can't look at == when deciding how to implement !=
> and vice versa.
>
> If it weren't for that, I'd be happy to say that default == is only
> permitted when != is also default. But it doesn't really matter, and in
> practice implementations will usually be able to detect the situation and
> issue a warning.
>
I'm afraid I must be missing something here.  If == is inline
(including auto on the declaration in the header) there is no problem,
and optimal versions of both can be generated.  Whether == is defined
in the same or a different translation unit, != must call == (since it
is not inline), whether it is auto or not.  To put it differently, I do
not see any semantic or implementation difference between "auto" and
"return !(*this==B).




James Dennett wrote:
> Manfred von Willich wrote:
> > If the rule is as you suggested it, that
> > <snip>
> > then if we write
> >     bool operator==(thisclass const & B) auto;
> >     bool operator!=(thisclass const & B) const { return nonsense(); }
> > then the operators == and != may be inconsistent.
>
> Not very relevant, in my estimation: it doesn't make
> it impossible to be inconsistent, but it does mean
> that natural code will be consistent.
>
> > Ergo, your suggestion does not necessarily avoid inconsistency between
> > == and !=, in apparently reasonable code.
>
> The code you show above is unreasonable, in my book.
> I've never had cause to implement operator!= as
> anything other than the negation of ==.
>
> > The benefit of being able to
> > say
> >     bool operator!=(thisclass const &) const auto;
> > instead of
> >     bool operator!=(thisclass const & B) const { return !operator==(B);
> > }
> > is rather doubtful, especially since the latter is more immediately
> > obvious.
>
> We can disagree there.
>
See my response to Dave above.  I presume that here you are referring
to what is more immediately obvious, not the value of the benefit,
which as I say is minimal.


> > C++ does not even pretend to encourage operator consistency - it lets
> > us hijack operators for unrelated uses (e.g. cout::operator<<).
>
> C++ does encourage consistency, it just doesn't enforce
> it at a language level (though the library requires a
> certain level of consistency).
>

How so?  At language level I think that aside from the
compiler-generated methods and the existing consistency with predefined
types, the apparently related operators are entirely unrelated.  Be
careful that you don't read your bias into the language.

Even at library level (e.g. a sort template or a polymorphic base
class), the requirements on comparison operators provided by a user
class are generally made very explicit, including exactly which
operators are used.  If a library template or polymorphic base class
uses both == and != (at least without catering specifically for
inconsistent semantics), such a library should be rewritten using only
one and the original author banished.  Where library classes intend to
use an intuitive meaning for most operators, this consistency has been
built in.  I do not read this as encouragement by C++ - only standard
style of usage.

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 30 Jun 2006 19:19:44 GMT
Raw View
yorara@terra.es (Zara) wrote (abridged):
> The suggested syntax is:
>
> class Whatever {
>     /*...*/
>     public:
>         Whatever() auto;
>         Whatever(const Whatever& ) auto;
>         Whatever operator=(const Whatever& ) auto;
>         virtual ~Whatever() auto;
>     /*...*/
> };

Putting the syntax in the declaration is conceptually wrong, in my view.
Whether a member is hand-crafted or compiler-generated is an
implementation detail that doesn't belong in the header.

It also takes away one use of the feature: dependancy management. My main
reason for defining members where the default implementation would do is
to remove that definition from the sight of clients. For example, I have
an intrusive smart pointer class which can be declared with incomplete
types:

     // Whatever.h
     #include "IntrusivePtr.hpp"

     class MyData;
     struct Whatever {
         IntrusivePtr<MyData> pData;

         Whatever( const Whatever &rhs );
     };

     // Whatever.cpp
     #include "MyData.hpp"

     Whatever::Whatever( const Whatever &rhs ) : pData( rhs.pData ) {
        // No code needed here, but the definition of MyData was
        // needed to copy pData.
     }

Doing this can avoid the need for clients to #include "MyData.hpp"
themselves. Being able to write:

    Whatever::Whatever( const Whatever &rhs ) = default;

would help.

-- Dave Harris, Nottingham, UK.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sat, 1 Jul 2006 14:03:35 GMT
Raw View
In article <e82tbk$at6$1@news.Stanford.EDU>, Seungbeom Kim
<musiphil@bawi.org> writes
>What we should have done is to make all constructors explicit by
>default, and let the keyword 'implicit' (or whatever) selectively mark
>those which aren't supposed to be explicit. Of course it's too late for
>any change like this, I know. :(


Unfortunately it was always too late. It is just one more example of
where standardising a widely used language resulted in second best
choices. Others are that functions should be local to a TU by default,
instead we have to declare them static to achieve that. Variables should
be immutable by default, instead we have to declare them const and so
on.


--
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Sat, 1 Jul 2006 17:34:07 CST
Raw View
Francis Glassborow wrote (abridged):
> See:
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1717.pdf
> the substance of which is likely to be in C++0x

So this thread has been directly preempted by work in progress - very
pleasing indeed.  Skimming this (IMO excellent) article, the concepts
have already been effectively covered.


Dave Harris wrote (abridged):
> Putting the syntax in the declaration is conceptually wrong, in my view.
> Whether a member is hand-crafted or compiler-generated is an
> implementation detail that doesn't belong in the header.

I fully I agree.  More correctly, it must be possible to omit the
auto/default from the declaration (and this should be preferred style
except for inline methods).  The article (n1717) has this angle very
nicely covered.


Would there be value in allowing the two following "explicitly default"
member functions, since IMHO they can be conveniently and safely added?
 These are
   bool operator== (Whatever const &) const;
   bool operator!= (Whatever const &) const;
Like the assignment and copy constructors, these can be unambiguously
defined in terms of the like operators of the base objects and member
objects (using && and ||) - using the same order as for construction,
including short-circuit evaluation.  (I also suggested this in a
another thread in this group).  If the necessary operators no not
exist, then the "default" version cannot be generated, as with copy
etc.

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 2 Jul 2006 17:52:50 GMT
Raw View
In article <1151766207.224845.246440@b68g2000cwa.googlegroups.com>,
Manfred von Willich <manfred@techniroot.co.za> writes
>Would there be value in allowing the two following "explicitly default"
>member functions, since IMHO they can be conveniently and safely added?
> These are
>   bool operator== (Whatever const &) const;
>   bool operator!= (Whatever const &) const;
>Like the assignment and copy constructors, these can be unambiguously
>defined in terms of the like operators of the base objects and member
>objects (using && and ||) - using the same order as for construction,
>including short-circuit evaluation.  (I also suggested this in a
>another thread in this group).  If the necessary operators no not
>exist, then the "default" version cannot be generated, as with copy
>etc.
The authors of 1717 (i.e. me and Lois Goldthwaite) are taking a
conservative line. We know that there are other candidates for our
'default' proposal but we would prefer that those be provided, in the
first instance, as extensions by compiler implementors until we are
certain that there are no unforeseen problems.

--
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: yorara@terra.es (Zara)
Date: Wed, 28 Jun 2006 13:21:14 GMT
Raw View
Up to now, there were three possibilities when definig classes:

- Explicitly define default constructor, copy constructor, copy
operator and destructor.

- Explicitly declare, but not define, them, to forbid their use.

- Let the compiler manage them.


I suggest the possibility to allow declaring them, but directing the
compiler to generate them as would have been if there was no
deckaration at all. This could be used by developers to guarantee this
member funcitons are always declared, be it for the sake of
completitude, or be it as an strict specification that a class is
manageable by the compiler.

The suggested syntax is:

class Whatever {
    /*...*/
    public:
        Whatever() auto;
        Whatever(const Whatever& ) auto;
        Whatever operator=(const Whatever& ) auto;
        virtual ~Whatever() auto;
    /*...*/
};

The virtual auto destuctor would be useful to make the class virtually
inheriatble, but frees the programmer from writing the contents of the
destructor, if the are nothing more than the default destructor, Of
course, this last case is nothign more than syntactic sugar (replacing
the really short virtual ~Whatever() {}), but would give a complete
maning to this feature.

And I think this isan easy upgrade to the standard, as:

- It would not break any existing code (or so I think)
- It does not add any new keyword, but overloads an existing ine
- The compiler is not forced to do any new task, as it is already
generating these default functions.

I am sorry this has been subjected too late for last meeting, but I
submit it anyway just in case it is possible to, at least, study it
for future meetings.

Standard regards,

Zara

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Manfred von Willich" <manfred@techniroot.co.za>
Date: Thu, 29 Jun 2006 14:34:59 CST
Raw View
Zara wrote:
> And I think this isan easy upgrade to the standard, as:
>
> - It would not break any existing code (or so I think)
> - It does not add any new keyword, but overloads an existing ine
> - The compiler is not forced to do any new task, as it is already
> generating these default functions.

True, as far as it goes.

> This could be used by developers to guarantee this
> member funcitons are always declared, be it for the sake of
> completitude, or be it as an strict specification that a class is
> manageable by the compiler.

I like your suggestion, but I feel it is incomplete (you should also
have some way of suppressing all compiler-generated members).  If the
compiler still generates the unmentioned members, I do not think this
achieves much.  For completeness or enforcing correctness, suppression
of the unmentioned members generation must be added.

I have longed for this "more complete" version - I find myself
laboriously suppressing individual members as you suggest, but find
this unsatisfactory.  I would have preferred no compiler-generated
members.  Then the class declaration would tell you exactly what member
functions are part of the class.

My variation of your suggestion would add a tweak (e.g. a "unadorned
class" syntax), e.g.

   class Whatever some_indicator {
      /* your suggested "auto" members as needed, adding "new" etc. */
   }

Other member functions to be considered for completeness include
operators such as new, delete, address-of, ->, dtor, assignment.  I am
not aware that this is an issue to most people.

Manfred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Andrei Polushin" <polushin@gmail.com>
Date: Thu, 29 Jun 2006 16:13:41 CST
Raw View
Manfred von Willich wrote:
> I like your suggestion, but I feel it is incomplete (you should also
> have some way of suppressing all compiler-generated members).  If the
> compiler still generates the unmentioned members, I do not think this
> achieves much.  For completeness or enforcing correctness, suppression
> of the unmentioned members generation must be added.
>
> I have longed for this "more complete" version - I find myself
> laboriously suppressing individual members as you suggest, but find
> this unsatisfactory.  I would have preferred no compiler-generated
> members.  Then the class declaration would tell you exactly what member
> functions are part of the class.
>
> My variation of your suggestion would add a tweak (e.g. a "unadorned
> class" syntax), e.g.
>
>    class Whatever some_indicator {
>       /* your suggested "auto" members as needed, adding "new" etc. */
>    }

What about "explicit class"?

  explicit class Whatever {
    // has no compiler-generated members unless you declare them
  };

--
Andrei Polushin

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: yorara@terra.es (Zara)
Date: Fri, 30 Jun 2006 05:22:55 GMT
Raw View
On Thu, 29 Jun 2006 16:13:41 CST, "Andrei Polushin"
<polushin@gmail.com> wrote:

>Manfred von Willich wrote:
>> I like your suggestion, but I feel it is incomplete (you should also
>> have some way of suppressing all compiler-generated members).  If the
>> compiler still generates the unmentioned members, I do not think this
>> achieves much.  For completeness or enforcing correctness, suppression
>> of the unmentioned members generation must be added.
>>
>> I have longed for this "more complete" version - I find myself
>> laboriously suppressing individual members as you suggest, but find
>> this unsatisfactory.  I would have preferred no compiler-generated
>> members.  Then the class declaration would tell you exactly what member
>> functions are part of the class.
>>
>> My variation of your suggestion would add a tweak (e.g. a "unadorned
>> class" syntax), e.g.
>>
>>    class Whatever some_indicator {
>>       /* your suggested "auto" members as needed, adding "new" etc. */
>>    }
>
>What about "explicit class"?
>
>  explicit class Whatever {
>    // has no compiler-generated members unless you declare them
>  };

I really like this last one. I would use it, I would refactor all my
code just to use it. My problem has been for a long time forgetting to
declare/undefine computer generated members, thus having some
unexpected results. Although now I am more careful, I have lots of
legacy code (*my* code) with such waiting-to-arise problem.

I think this improvement, the "explicit" class, with the computer
genrated members labeled as "auto" would be a nice way to give
programmers some extra powerwithout breaking any existing code, and
allowing a fast refactoring of legacy code.

Zara

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Fri, 30 Jun 2006 14:26:18 GMT
Raw View
In article <1151614118.297138.234320@j72g2000cwa.googlegroups.com>,
Andrei Polushin <polushin@gmail.com> writes
>What about "explicit class"?
>
>  explicit class Whatever {
>    // has no compiler-generated members unless you declare them
>  };
See:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1717.pdf

the substance of which is likely to be in C++0x


--
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: musiphil@bawi.org (Seungbeom Kim)
Date: Fri, 30 Jun 2006 14:27:18 GMT
Raw View
Zara wrote:
>
> I suggest the possibility to allow declaring them, but directing the
> compiler to generate them as would have been if there was no
> deckaration at all. This could be used by developers to guarantee this
> member funcitons are always declared, be it for the sake of
> completitude, or be it as an strict specification that a class is
> manageable by the compiler.
>
> The suggested syntax is:
>
> class Whatever {
>     /*...*/
>     public:
>         Whatever() auto;
>         Whatever(const Whatever& ) auto;
>         Whatever operator=(const Whatever& ) auto;
>         virtual ~Whatever() auto;
>     /*...*/
> };
>
> The virtual auto destuctor would be useful to make the class virtually
> inheriatble, but frees the programmer from writing the contents of the
> destructor, if the are nothing more than the default destructor, Of
> course, this last case is nothign more than syntactic sugar (replacing
> the really short virtual ~Whatever() {}), but would give a complete
> maning to this feature.

(FYI, I've seen similar proposals with the alternative keyword 'default'
- you may want to look for them.)

I see little benefit in declaring the default constructor or the
destructor with 'auto', but I can see that declaring the copy
constructor or the assignment operator in such a way might make it
a little easier to declare them protected without changing the
implied behaviour.

However, only up to that point; the benefit is limited. You may want
to augment the default behaviour with additional operations. Then
we could make it even more useful by the following syntax:

    class Whatever
    {
    public:
        Whatever(const Whatever&);
        Whatever& operator=(const Whatever&);

    private:
        // just an example of lots of members to take care of
        int one, two, three, four, five;
    };

    Whatever::Whatever(const Whatever& other) :
        /*  instead of
         *  one(other.one), two(other.two), ...
         */
        default(other)
    {
        std::clog << "copy constructor\n";
    }

    Whatever& Whatever::operator=(const Whatever& other)
    {
        /*  instead of
         *  one = other.one;
         *  two = other.two;
         *  ...
         */
        default::operator=(other);
        std::clog << "assignment operator\n";
    }

In case you don't want to change their behaviour but just to declare
them with a different access specifier, the following syntax can be used
as a short-cut:

    class Whatever
    {
    protected:
        Whatever(const Whatever&) = default;
        Whatever& operator=(const Whatever&) = default;
        virtual ~Whatever() = default;
        // ...
    };

I consider this syntax as more consistent with the current language
rules, because keywords placed right after the closing parenthesis
in a function declaration (const and throw) have been part of the
function signature, but '= 0' has not, and specifying 'default' should
not be part of the function signature. (Yes, there is a problem if
you want to make a function both pure virtual and default, but you
can always use the first syntax; it's no worse than currently having
to define a pure virtual function outside the class definition if
you want to define one.)

--
Seungbeom Kim

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: musiphil@bawi.org (Seungbeom Kim)
Date: Fri, 30 Jun 2006 14:28:00 GMT
Raw View
Zara wrote:
> On Thu, 29 Jun 2006 16:13:41 CST, "Andrei Polushin"
> <polushin@gmail.com> wrote:
>
>> What about "explicit class"?
>>
>>  explicit class Whatever {
>>    // has no compiler-generated members unless you declare them
>>  };
>
> I really like this last one. I would use it, I would refactor all my
> code just to use it. My problem has been for a long time forgetting to
> declare/undefine computer generated members, thus having some
> unexpected results. Although now I am more careful, I have lots of
> legacy code (*my* code) with such waiting-to-arise problem.
>
> I think this improvement, the "explicit" class, with the computer
> genrated members labeled as "auto" would be a nice way to give
> programmers some extra powerwithout breaking any existing code, and
> allowing a fast refactoring of legacy code.

It makes the explicit class look like a different kind of class,
doesn't it? Whether a class has certain compiler-generated member
function or not - I don't find it that important a property to be
entitled to qualify the entire class definition.

Instead, a better way would be to turn off generation of each
compiler-generated members, individually. Along the lines of the
proposed syntax in my previous posting, we could adopt something like:

    class Whatever // non-copyable
    {
    public:
        // ...
        Whatever(const Whatever&) != default;
        Whatever& operator=(const Whatever&) != default;
        // The default constructor and the destructor are
        // still automatically generated by the compiler.
    };

Regarding the keyword explicit, I regret having it as it is now;
the rules are very inconsistent. If a constructor requires two or more
arguments, it is inherently explicit; if a constructor can be called
with only one argument, it is non-explicit (or 'implicit') by default,
and should be explicitly marked 'explicit'. Suppose you have a
constructor which required two arguments, whose explicitness you have
relied on, and later you supply a default to the second argument, then
you suddenly make it non-explicit without noticing it.

What we should have done is to make all constructors explicit by
default, and let the keyword 'implicit' (or whatever) selectively mark
those which aren't supposed to be explicit. Of course it's too late for
any change like this, I know. :(

--
Seungbeom Kim

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]