Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Proper type for initialization lists (proposal)

5 views
Skip to first unread message

Vidar Hasfjord

unread,
Dec 15, 2006, 8:29:49 AM12/15/06
to
An initialization list (IL) is a kind of literal without proper typing
in the C++ language today. There is a proposal for C++0x to generalize
the IL (N2100). Unfortunately, the proposal doesn't assign proper type
to ILs. It merely views an IL as an ad-hoc list of types "{T1, T2,
...}" and proposes a mechanical transformation of an IL to a new type
(intializer_list <T>). This type doesn't fully describe an IL, and thus
does not support useful constructs on ILs such as:

auto keywords = make_array ({"char", ...});

The reason is that there is no way to deduce the size of the array from
the type initializer_list. With variadic templates and generalized
tuples the above can be written like the following conceptual
equivalent (that works):

auto keywords = make_array (make_tuple ("char", ...));

Hence I propose an alternative view of ILs in terms of tuples. My
proposal is based on the variadic template proposal (N2080). In
addition I propose a formalization of aggregate initialization in terms
of tuples, as well as rules for implicit conversions between tuples and
arrays.

I propose that the type of an IL with a sequence of values of types
(T1, T2, ..., TN) is defined as (tuple <T1, T2, ..., TN>). This require
a general tuple type defined in terms of the variadic template
proposal.

Using this definition of the type of an IL, all language constructs
that involve ILs are expressed in terms of tuples as follows.

Traditional initialization of aggregates without explicit constructors
is defined in terms of an implicit (auto-generated) constructor:

struct S {
A a; B b; // ...

// implicit constructor
template <class... Args>
S (tuple <Args>& t)
: a (get <0> (t)), b (get <1> (t)) ... {}
};

S s = {1, 2};
// Equivalent to:
S s = tuple (ref (1), ref (2));

The wrapping of arguments is necessary to allow direct initialization
of aggregates that contain references:

struct ARef {
A& ra;
};

A a = 1;
ARef r = {a};
// Equivalent to:
ARef r = tuple (ref (a));
r.ra = 2; assert (a == 2);

Initialization of arrays is viewed in terms of an implicit conversion
from (tuple <Args>) to (T [N]) where Convertible <T, Args> and N ==
mpl::size <Args>::value. For example:

int a [2] = {1, 2};
// Equivalent to:
int a [2] = static_cast <int [2]>
(tuple (ref (1), ref (2)));

The use of initializer lists to initialize user-defined types with
explicit constructors is achieved by a templated constructor with a
tuple parameter:

class Foo {
public:
template <class... Args>
Foo (const tuple <Args>& t);
};

Foo f = {1, 2, 3};
// Equivalent to:
Foo f = tuple (ref (1), ref (2), ref (3));

Note that the constructor needn't be variadic nor templated if the
tuple size and element types are fixed. For example:

class Bar {
public:
Bar (const tuple <string, int>& t);
};

Bar b = {"John", 42}; // ok

Additionally, user-defined sequence types can also rely on the implicit
conversion of a tuple into an array. This allows a simpler non-variadic
templated contructor:

template <class T>
class vector {
public:
template <size_t N>
vector (T (&a) [N]) : vector (a, a + N) {} // forward
// ...
};

vector <int> v = {1, 2};
// Equivalent to:
vector <int> v = vector <int> (
static_cast <int [2]>
(tuple (ref (1), ref (2)))
);

This requires the language to try the (tuple -> array) conversion when
matching template parameters to arguments. The language currently does
not consider any implicit conversions when matching template
parameters. This extension could be limited to where ILs occur.

Ok. That's the gist of my proposal. I have ignored a great multitude of
details, and I'm sure I've overlooked a lot of things, so I welcome
your feedback.


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

0 new messages