lmi
[Top][All Lists]
Advanced

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

Re: [lmi] Switch to using C++11 uniform initialization in the ctor initi


From: Greg Chicares
Subject: Re: [lmi] Switch to using C++11 uniform initialization in the ctor initializer lists?
Date: Fri, 24 Aug 2018 02:03:10 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1

On 2018-08-23 23:24, Vadim Zeitlin wrote:
> On Thu, 23 Aug 2018 19:52:57 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> On 2018-08-23 18:20, Vadim Zeitlin wrote:
> [...]
> GC> >  I do get quite a few errors after switching to {}. Especially worrisome
> GC> > are those that resulted from initially incorrectly changing std::deque 
> and
> GC> > std::vector ctors to use {} instead of (): this actually changed the 
> code
> GC> > meaning, as with () it used the "traditional" ctor, from C++98, while 
> with
> GC> > {} it started using ctor taking std::initializer_list.
> GC> 
> GC> Are there any other types of errors, aside from those especially
> GC> worrisome ones?
> 
>  Yes, size_t to int conversions in the initializations of int members with
> x.size(). I've fixed those for now using lmi::ssize(x) instead, but this is
> not really a totally correct fix as under Win64 with MSVC, ssize_t is
> strictly greater than int. However I think that if we want to support this
> platform (note that the problem doesn't arise with gcc), we should rather
> change ssize_t to be int there as the whole point of ssize_lmi.hpp is to
> make size_t interoperable with int, not with some possibly-larger-than-int
> signed integer type.

Wow, I hadn't thought of that. Yes, it seems that
  using ssize_t = int;
is the best way. Two out of three functions in 'ssize_lmi.hpp' already
use bourn_cast, so the documented precondition ought to be enforced for
a modified ssize_t in those cases; I'll want to examine the unit test
to make sure that's covered. I'm not sure the array[n] function is
robust enough--maybe it should be changed thus:
-    return {n};
-    return bourn_cast<ssize_t>(n);
I'll have to look through old emails and commit messages, because I'm
pretty sure I documented some reason for not doing that originally.

> GC> >  This raises 2 questions:
> GC> > 
> GC> > 1. How should the code using these ctors, e.g. the initialization of
> GC> >    seriatim_keywords_ and seriatim_numbers_ in input_sequence.cpp be
> GC> >    actually written? For now I'm keeping () as it seems the most robust 
> and
> GC> >    also, arguably, the clearest things to do (the latter because it 
> draws
> GC> >    attention to the fact that this is not just a simple initialization 
> but
> GC> >    a call to a ctor which does something less trivial).
> GC> 
> GC> Yes, that sounds best. There isn't any reasonable alternative, is there?
> 
>  AFAIK you can't prevent ctor taking std::initializer_list from being used
> if it can be used

I thought of adding something like
  foo::foo(std::initializer_list<whatever>) = delete;
but didn't spend a moment considering whether that would even work,
because it's just too ugly.

> so the only alternative I see is to have a function like
> this:
> 
>       template <typename T>
>       std::vector<T>
>       make_vector_of_size(std::size_t size, T value = T{})
>       {
>           return std::vector(size, value);
>       }
> 
> and using
> 
>       :vec_{make_vector_of_size(10, 11)}
> 
> to make a vector of size 10 filled with 11 instead of a vector of size 2
> with 10 and 11 in it as we'd get from
> 
>       :vec_{10, 11}
> 
>  Of course, this is (a) cheating, as we just hide the parentheses inside a
> helper function and (b) more verbose. But OTOH this is arguable more clear.
> I must admit that I initially wrote this as a proof that there is indeed no
> reasonable alternative

At this point I'd just write "QED" and be done with it.

> but the more I think it, more I actually like this
> idea as it's just much more readable than a raw ctor call.

No, really? It seems weird to introduce an auxiliary function just to
initialize a standard container. If we were taking maintainership of
an orphaned C++ library (as you and Vaclav did for xmlwrapp) and it
had such a thing, wouldn't we consider removing in order to render
the code comprehensible?

You might say that this is like std::make_pair<>(), but my impression
is that there's no need for that anymore, precisely because of uniform
initialization. For example, in free function apportion(), I was about
to use it in the queue.push() line, but then I realized that I could
just use '{}'...and I walked away from that experience thinking that
we ought to eliminate std::make_pair elsewhere, too.

> GC> One idea is not to modernize container construction. I'm guessing
> GC> that 'ContainerType z(anything)' will rarely if ever be compatible
> GC> with '{}' in the lmi corpus.
> 
>  AFAICS, even never. I guess I can live with an inconsistency between
> containers and everything else, but maybe it's worth introducing
> make_container_of_size() to avoid it?

I'd better sleep on it and take a fresh look on a different day,
but I suspect that container initializers with '()' will stand out
so clearly against an otherwise-uniform '{}' background as to be
immediately clear.



reply via email to

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