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! ]