[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] Default values for default arguments
From: |
Vadim Zeitlin |
Subject: |
Re: [lmi] Default values for default arguments |
Date: |
Sat, 11 Feb 2017 17:59:45 +0100 |
On Sat, 11 Feb 2017 10:44:00 +0000 Greg Chicares <address@hidden> wrote:
GC> On 2017-02-11 10:16, Greg Chicares wrote:
GC> > On 2017-02-10 16:58, Vadim Zeitlin wrote:
GC> >>
GC> >> I'd also consider using "Foo{}" instead of "Foo()" for the constructors
of
GC> >> temporary objects (although lmi code doesn't use them much, I think),
GC> >> because the former is much more clear as it doesn't look like a function
GC> >> call.
GC> >
GC> > Discussion of selected `grep 'std::string()'` results:
GC> >
GC> > datum_sequence.cpp: return std::string();
GC> > rate_table_test.cpp: stream_out_.str(std::string());
GC> > rate_table_tool.cpp: name_map.emplace(num, std::string());
GC> >
GC> > In those cases, the type 'std::string' must be named, and I think you're
GC> > saying you'd prefer {} to ().
Yes, I prefer it, but just because it seems more readable to me and I
realize that it's not an objective argument.
GC> > antediluvian_stubs.cpp: std::string const empty_string = std::string();
GC> >
GC> > How about that one? Which of the following...
GC> > std::string const empty_string = std::string(); // Leave it alone.
GC> > std::string const empty_string = std::string{}; // Prefer {} to ().
GC> > std::string const empty_string{}; // Don't even name the type.
If it's a variable declaration, then I definitely prefer the last one,
repeating the type here doesn't seem to serve any useful purpose. The
real choice here for me is between
std::string const empty_string{}; // Don't even name the type.
std::string const empty_string; // Shortest possible.
Here I also (slightly) prefer the version with "{}" and I think I do have
an objective argument in favour of it: consistency with the primitive
types. For std::string the two lines are exactly equivalent, but
double zero_double{};
double uninitialized_double;
are not and using "{}" makes things more clear.
GC> > wx_test_paste_census.cpp: ,std::string const& unexpected =
std::string()
GC> >
GC> > How about this one, which is a defaulted argument? I ask this because
GC> > earlier we had decided to write that exactly as above. But it's okay
GC> > to change our minds; which would you now prefer?
GC> > ,std::string const& unexpected = std::string()
GC> > ,std::string const& unexpected = std::string{}
GC> > ,std::string const& unexpected{}
The last one shouldn't compile AFAICS. If you meant
,std::string const& unexpected = {}
then we already discussed that it doesn't use the ctor you might expect it
to use (but the one from the initializer_list), so IMHO it's confusing. And
between the two remaining variants, I prefer the one with "{}" for
consistency with the other cases.
GC> And how about ctor initializer lists?
Generally speaking, they should be used less often in C++11 because member
initialization is preferable, whenever possible.
GC> In HEAD at this moment we have:
GC>
GC> struct ValueInterval
GC> {
GC> ValueInterval();
GC>
GC> double value_number;
GC> std::string value_keyword;
GC> bool value_is_keyword;
GC> int begin_duration;
GC> duration_mode begin_mode;
GC> int end_duration;
GC> duration_mode end_mode;
GC> bool insane;
GC> };
GC>
GC> whose ctor follows my old practice of eliding non-POD members for which
GC> default values are wanted, so std::string 'value_keyword' is omitted here:
GC>
GC> ValueInterval::ValueInterval()
GC> :value_number (0.0)
GC> ,value_is_keyword (false)
GC> ,begin_duration (0)
GC> ,begin_mode (e_duration)
GC> ,end_duration (0)
GC> ,end_mode (e_duration)
GC> ,insane (false)
GC> {}
In this case I would definitely initialize all members in their
declaration, i.e.
struct ValueInterval
{
ValueInterval() = default; // Unnecessary, but more clear.
double value_number = 0.0;
std::string value_keyword;
bool value_is_keyword = false;
int begin_duration = 0;
duration_mode begin_mode = e_duration;
int end_duration = 0;
duration_mode end_mode = e_duration;
bool insane = false;
};
Whether you want to initialize value_keyword here or not is a matter of
taste, I don't think it's really necessary, but maybe it would be better to
do it just for consistency.
GC> Today I look at that as a symmetry violation, and I want to add
GC>
GC> :value_number (0.0)
GC> + ,value_keyword WHAT?
GC> ,value_is_keyword (false)
GC>
GC> but how should that be initialized? Options:
GC>
GC> ,value_keyword (std::string()) // #1
GC> ,value_keyword ("") // #2
GC> ,value_keyword () // #3
GC> ,value_keyword {} // #4
GC>
GC> I think #1 is ugly, #2 is poor, and #3 introduces its own asymmetry
^
|
~~~
After some initial confusion, I think you meant "#4" here.
GC> if we leave the others as they are:
GC>
GC> :value_number (0.0) // parentheses
GC> ,value_keyword {} // braces?
GC> ,value_is_keyword (false) // parentheses
GC>
GC> so should we instead change all the parentheses to braces?
Yes, I think we should. But, of course, first we should remove all the
unnecessary initializer list elements (i.e. those that can be replaced with
just member initialization as shown above), so there might be not that many
parentheses to change.
GC> I don't think we want to make that a general rule because we might
GC> someday have a similar case that uses lmi's class glossed_string
GC> instead of std::string, and glossed_string has std::initializer_list
GC> ctor, so the meaning of 'glossed_string{}' changes from C++11 to C++17.
Sorry if I'm missing something, but glossed_string doesn't have a ctor
from std::initializer_list and it doesn't seen desirable to add one, so
what does this prove?
GC> Therefore, I think our general rule here should be #3:
GC> ,value_keyword () // datatype is std::string
GC> if we want to write it at all.
I don't think we want to write initializers for the members which are
already initialized anyhow, which includes both the members having an
initializer in their declaration and member objects with default ctor.
Regards,
VZ
- Re: [lmi] Third-millennium GOTW#1: is <int> special?, (continued)
- Re: [lmi] Third-millennium GOTW#1: is <int> special?, Greg Chicares, 2017/02/05
- Re: [lmi] Third-millennium GOTW#1: is <int> special?, Vadim Zeitlin, 2017/02/06
- [lmi] More enabled warnings, less boost [Was: Third-millennium GOTW#1: is <int> special?], Greg Chicares, 2017/02/06
- Re: [lmi] More enabled warnings, less boost, Vadim Zeitlin, 2017/02/06
- Re: [lmi] More enabled warnings, less boost, Greg Chicares, 2017/02/06
- Re: [lmi] More enabled warnings, less boost, Vadim Zeitlin, 2017/02/06
Re: [lmi] Default values for default arguments, Greg Chicares, 2017/02/10
- Re: [lmi] Default values for default arguments, Vadim Zeitlin, 2017/02/10
- Re: [lmi] Default values for default arguments, Greg Chicares, 2017/02/11
- Re: [lmi] Default values for default arguments, Greg Chicares, 2017/02/11
- Re: [lmi] Default values for default arguments,
Vadim Zeitlin <=
- Re: [lmi] Default values for default arguments, Greg Chicares, 2017/02/11
- Re: [lmi] Default values for default arguments, Vadim Zeitlin, 2017/02/11
[lmi] () or {} in initializer lists [Was: Default values for default arguments], Greg Chicares, 2017/02/22
Re: [lmi] () or {} in initializer lists [Was: Default values for default arguments], Vadim Zeitlin, 2017/02/22
Re: [lmi] () or {} in initializer lists [Was: Default values for default arguments], Greg Chicares, 2017/02/26
Re: [lmi] () or {} in initializer lists, Vadim Zeitlin, 2017/02/26