Re: Type of initializer lists ( N2215 feedback)
Vidar Hasfjord wrote:
On Apr 1, 9:09 pm, "Mathias Gaunard" <loufo...@gmail.com> wrote:
You could very well do auto a = std::make_array( { /* ... */ } ); if
the lists carries the size information.
Which is exactly my point. Unfortunately the initializer_list type as
proposed in N2215 does not carry the size.
(The value does however carry size as a constexpr which can be
evaluated at compile time. But can you transport it from the value
domain to the type domain? I don't see how.)
If were a true constexpr, this would be easy. For example:
template <class Init>
std::array< typename Init::value_type, Init::size() >
make_array( Init&& init ) {
std::array< typename Init::value_type, Init::size() > rv = init;
return rv;
}
But as I understand it, size() isn't a proper constexpr -- see 4.5.7 in
n2215. What's more, where there is only one instantiation of make_array
per type of Init, and the value of the initalizer_list's size isn't
folded into its type, even if some compiler magic can make it work when
it's first instantiated, the fact that the same instantiation is shared
between different sized initalizer_lists, breaks this.
Stroustrup gave an interesting talk on this subject at the ACCU
conference last week. He mentioned, while discussing alternative
syntaxes that had been suggested, that they had considered using
template <class T, std::size_t N>
foo::foo( T (&)[N] ) {}
as the syntax for the sequence constructor, but had rejected it
precisely because it folded the size, N, into the type system.
This could probably be solved in the same way that template argument
deduction works for built-in arrays -- via type decay. And we could do
this via inheritance in the library:
template <class T, std::size_t N>
struct sized_initializer_list : initalizer_list<T> {
typedef std::size_t size_type;
constexpr size_type size() { return N; }
};
(and remove the 'constexpr' keyword from the base class size() method as
it isn't really true.)
Then we define the type of {1,2,3} to be sized_initializer_list<int,3>
and it all works. (By virtue of the last bullet point of 14.8.2.1/3,
the derived-to-base conversion will occur during template argument
deduction for a parameter of the form initializer_list<T>.)
This way, when we know that we don't care about the size of the array
(for example in a vector sequence constructor), we can drop it from the
type system and not instantiate one constructor per initializer list
size. And when we do need it (for example, with a make_array function),
we can still have it. And in the case of a general forwarding function:
template <typename T, typename... Args>
std::unique_ptr<T>
safe_new( Args&&... args ) {
return std::unique_ptr<T>
( new T( std::forward<Args>(args)... );
}
(excuse an errors in the variadic function syntax), the derived-to-base
conversion will *not* happen and our initializer list gets forwarded
complete with size.
Having said that, yes, I would like to see support for heterogenous
initializer lists, probably using some form tuple-like type. I would
imagine that with some concept trickery, this could be made to work
nicely: heterogenous initializer lists would be std::tuples, homogenous
initializer lists would be std::initializer_lists and by judicious use
of concepts we shouldn't care which we've been given. Perhaps.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]