lmi
[Top][All Lists]
Advanced

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

Re: [lmi] Specializing std::numeric_limits?


From: Vadim Zeitlin
Subject: Re: [lmi] Specializing std::numeric_limits?
Date: Sun, 7 Mar 2021 15:07:02 +0100

On Sun, 7 Mar 2021 13:36:06 +0000 Greg Chicares <gchicares@sbcglobal.net> wrote:

GC> On 3/6/21 11:41 PM, Vadim Zeitlin wrote:
GC> > On Sat, 6 Mar 2021 23:24:09 +0000 Greg Chicares <gchicares@sbcglobal.net> 
wrote:
GC> [...]
GC> > GC> Vadim--Is std::numeric_limits as rarely specialized in practice as I
GC> > GC> infer from the meagerness of stackexchange discussions on this topic?
GC> > 
GC> >  I don't really know, but IMHO it doesn't make much sense to specialize it
GC> > for user-defined types, even if it is indeed allowed as some people seem 
to
GC> > think. I've always thought of this class as providing information about 
the
GC> > properties of arithmetic types of the concrete implementation and from 
this
GC> > point of view specializing it would only be useful if you could also 
define
GC> > new arithmetic types, but you can't do this.
GC> 
GC> Interesting--yes, it can be seen as a C++-ization of the C macros that
GC> define properties of built-in arithmetic types.

 This is indeed exactly how I view it. I could be wrong, of course, not
everything is defined by its history, but I still suspect that the main
motivation for adding std::numeric_limits<> was to replace the C macros and
not to provide some generic mechanism for providing type-dependent
information applicable to user-defined types.

GC> > GC> At any rate, lmi's class template minmax was originally intended to 
provide
GC> > GC> a "safe" cover for std::minmax_element(), hiding the pointers (which 
until
GC> > GC> today could have been null, so it wasn't safe) behind functions.
GC> > 
GC> >  Sorry, I couldn't understand this part. Which pointers do you mean here?
GC> 
GC> std::minmax_element() returns std::pair<ForwardIterator,ForwardIterator>,
GC> and I loosely referred to the forward iterators as "pointers".

 Oops, sorry, I've simply completely forgotten that std::minmax_element()
returned iterators and not values, sorry.

GC> > GC> Then it was enhanced, using std::numeric_limits to set a priori
GC> > GC> extrema...which were not "meaningful" according to the Standard
GC> > GC> in all actual use cases (fixed now). So we could have
GC> > GC> instantiated minmax<some_random_class> whose minimum() and
GC> > GC> maximum() would both have either returned zero, or segfaulted.
GC> > 
GC> >  If this class is only supposed to be used with arithmetic types (or maybe
GC> > even only floating point ones? AFAICS it's only used with double outside 
of
GC> > the tests), shouldn't we (statically) assert this fact directly?
GC> 
GC> It could just as well be used for integers. There's no need to forbid
GC> that, even though lmi hasn't yet used it that way.

 We seem to have a rather deep philosophical difference here. I believe
that everything that is not needed should be forbidden by default, i.e. I'm
extremely authoritarian in design of my classes (as opposed to everything
else). Maybe it's just professional library developer deformation (because
the difference is definitely much smaller inside a single program which is
entirely under your control -- but smaller doesn't mean inexistent nor even
small), but I very strongly feel that it's so much simpler to add a feature
later, compared to modifying or removing an existing feature, that it is
almost never worth adding anything before it is actually absolutely needed.
I.e. I always prefer to use write-on-demand approach rather than writing
something just because it might be useful in the future.


GC> >  BTW, on a completely different note, looking at this code:
GC> > 
GC> >   auto const& extrema = std::minmax_element(v.begin(), v.end());
GC> >   minimum_ = *extrema.first ;
GC> >   maximum_ = *extrema.second;
GC> > 
GC> > I think it could be one of the few cases where std::tie() could be 
actually
GC> > useful, as it would allow writing this as
GC> > 
GC> >   std::tie(minimum_, maximum_) = std::minmax_element(v.begin(), v.end());
GC> > 
GC> > which is IMHO slightly more readable.
GC> 
GC> But that doesn't dereference the iterators:

 Yes, of course, because I forgot everything about iterators being even
used here and didn't bother actually compiling this code to check my
suggestion. Sorry again.

GC> And I don't think "structured bindings" can be used to set data members, 
e.g.:
GC>   [minimum_, maximum_] = std::minmax_element(v.begin(), v.end());

 No, they definitely can't, which is why I had suggested using std::tie().
As it is, the best I can suggest is doing

        auto const& [min_it, max_it] = std::minmax_element(v.begin(), v.end());
        minimum_ = *min_it;
        maximum_ = *max_it;

which is not nearly as nice as a single-line solution, all it does is to
replace the "first" and "second" fields with more descriptive names which
is still nice, IMHO, but probably not worth it.

 Regards,
VZ

Attachment: pgpEuSYEswXTU.pgp
Description: PGP signature


reply via email to

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