From: Vidar Hasfjord on
I've just read N2575 and welcome its proposals. N2575 takes a step
back and provides a simple but brilliant programmer's perspective: the
division of concerns into conversions and constructor calls.

Here's some feedback.

1. In my view conversion is the important feature of the initializer
list proposals. The other feature, an alternative syntax for
constructor calls, I find odd and unnecessary. These syntax extensions
are confusing parameter lists and initializer lists and add another
idiosyncrasy to the language. I would prefer parantheses for
constructor calls to always be required and to view curly brackets
simply as list construction.

2. I have a gut reaction against std::initializer_list being a built-
in type. A stated important goal of the proposals is to erase the
special treatment of built-in types. With that in mind the
introduction of a new built-in type with special treatment smells bad.
The partial built-in status and library implementation is strange.
Also, there is already a library type, std::tuple, that better
encapsulates an initializer list. Hence it is odd that a lesser type
should be preferred.

My thoughts on initializer lists:

An initializer list is an object of unnamed built-in tuple type. This
type is a restricted incomplete type. You can do very little with it
until it has manifested itself. The initializer list seeks to manifest
itself by converting to another type. Unless an explicit conversion is
applied the initializer list looks for a matching constructor or
conversion.

1. The best match is a non-explicit unconstrained variadic constructor
template. A type such as std::tuple is a perfect match as it fully
describes an initializer list; i.e. the number and types of the
elements.

2. Second-best match is a non-explicit constrained variadic
constructor template. A type such as std::initializer_list is a good
match. Concepts constrain the std::initializer_list variadic
constructor template to only accept homogenous lists. Here
std::initializer_list is an ordinary library type.

3. Implicit constructors and conversion operators are attempted. The
initializer list looks for matching number of parameters and type
according to N2575/N2531. Implicit conversions of the elements are
tried if no perfect matches are found.

Aside: Whether narrowing conversions should be allowed is a
controversial issue. My inkling is that they should not be allowed,
but that their omission should not disambiguate matches (causes
surprises). E.g. {1, 1.1} should not match (int, int), but should
neither select (int, double) if both are available. It should be
ambiguous.

How do existing uses of initializer lists fit with this view?

int a [3] = {1, 2, 3.0};

This is defined to work by converting the initializer list on the
right to an array using a built-in variadic constructor template for
arrays. This built-in constructor handles implicit conversion. (This
allows current narrowing without requiring narrowing to be the general
rule.)

struct A {int x; int y;} a = {1, 2.0};

This is defined to work by converting the initializer list on the
right to an instance of A using a built-in constructor taking
parameters (int, double). This means that the constructor call A (1,
2.0) is now allowed without declaring a constructor for A. (Again,
these automatically generated constructors takes care of the narrowing
issue.)

In summary, the overarching ideal for a solution to initializer lists
is in my view to erase the special treatment of built-in types. My
benchmark:

int a [] = {1, 2, 3}; // size deduced
std::array <int, auto> = {1, 2, 3}; // should also work

Reference:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2575.pdf

Regards,
Vidar Hasfjord

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]