Topic: Why is std::array an aggregate?
Author: Scott Meyers <NeverRead@aristeia.com>
Date: Fri, 18 Dec 2009 15:00:50 CST Raw View
In TR1, std::tr1::array needed to be an aggregate so that it could be
brace-initialized. To offer the same capability for C++0x's std::array, the
class could simply declare a constructor taking a std::initializer_list. So why
is std::array an aggregate? Making it a non-aggregate would permit e.g., giving
it a constructor taking a pair of iterators.
Thanks for all illumination.
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: James Kanze <james.kanze@gmail.com>
Date: Sat, 19 Dec 2009 00:55:43 CST Raw View
On Dec 18, 9:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
> In TR1, std::tr1::array needed to be an aggregate so that it
> could be brace-initialized. To offer the same capability for
> C++0x's std::array, the class could simply declare a
> constructor taking a std::initializer_list. So why is
> std::array an aggregate? Making it a non-aggregate would
> permit e.g., giving it a constructor taking a pair of
> iterators.
Presumably, so that it can be statically initialized, in order
to avoid order of initialization problems. (It still needs a
mechanism for the number of elements to be determined,
statically, from the initialization list, in order to be truly
useful.)
--
James Kanze
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <NeverRead@aristeia.com>
Date: Sat, 19 Dec 2009 21:37:48 CST Raw View
James Kanze wrote:
> Presumably, so that it can be statically initialized, in order
> to avoid order of initialization problems. (It still needs a
> mechanism for the number of elements to be determined,
> statically, from the initialization list, in order to be truly
> useful.)
Well, the size of the std::array is part of its type, so if dynamic
initialization were permitted, all we'd need would be a specification for what
happens if the number of clauses in the init list didn't match the declared size
of the std::array. To keep things semi-consistent with aggregate
initialization, we could say that std::array elements without initializers would
be value initialized, and if too many initializers were specified, an exception
would be thrown.
Actually, now that I think of it, I'm pretty sure std::array objects can be
dynamically initialized:
std::array<int, 3> a { f(), g(), h() }; // legal, no?
As for avoiding order of initialization problems, why should std::array be
special in this regard?
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Sun, 20 Dec 2009 12:21:57 CST Raw View
James Kanze wrote:
> On Dec 18, 9:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
>> In TR1, std::tr1::array needed to be an aggregate so that it
>> could be brace-initialized. To offer the same capability for
>> C++0x's std::array, the class could simply declare a
>> constructor taking a std::initializer_list. So why is
>> std::array an aggregate? Making it a non-aggregate would
>> permit e.g., giving it a constructor taking a pair of
>> iterators.
>
> Presumably, so that it can be statically initialized, in order
> to avoid order of initialization problems.
>
I believe this can all be done using variadic templates:
template<typename T, size_t S>
struct array {
template<typename ...U>
constexpr array(U&&... u):elems{ u... } { }
T elems[S];
};
array<int, 3> a = { 1, 2 }; // works, is statically initialized
array<int, 2> a = { 1, 2, 3 }; // gives an error at compile time
It doesn't seem to be that we can use static_cast or std::forward here to
enable move semantics, as i think it will render the initializers to non-
potential-constant-expressions.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: James Kanze <james.kanze@gmail.com>
Date: Sun, 20 Dec 2009 12:22:32 CST Raw View
On 20 Dec, 03:37, Scott Meyers <NeverR...@aristeia.com> wrote:
> James Kanze wrote:
> > Presumably, so that it can be statically initialized, in order
> > to avoid order of initialization problems. (It still needs a
> > mechanism for the number of elements to be determined,
> > statically, from the initialization list, in order to be truly
> > useful.)
> Well, the size of the std::array is part of its type, so if
> dynamic initialization were permitted, all we'd need would be
> a specification for what happens if the number of clauses in
> the init list didn't match the declared size of the
> std::array. To keep things semi-consistent with aggregate
> initialization, we could say that std::array elements without
> initializers would be value initialized, and if too many
> initializers were specified, an exception would be thrown.
That still means you have to write the size. An exception isn't
as good as a compiler error, and a compiler error isn't as good
as not having to write the size to begin with.
> Actually, now that I think of it, I'm pretty sure std::array
> objects can be dynamically initialized:
> std::array<int, 3> a { f(), g(), h() }; // legal, no?
Of course they can. So can C style arrays:
int a[] = { f(), g(), h() };
> As for avoiding order of initialization problems, why should
> std::array be special in this regard?
What's special is that it can also be initialized statically:
std::array< int, 3 > a = { 1, 2, 3 };
Regardless of where this definition appears, I'm guaranteed that
it occurs before *any* user defined code, including code in
constructors of other static objects. In certain cases, that's
a useful guarantee.
--
James Kanze
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Faisal Vali <faisalv@gmail.com>
Date: Sun, 20 Dec 2009 22:00:47 CST Raw View
On Dec 19, 12:55 am, James Kanze <james.ka...@gmail.com> wrote:
> On Dec 18, 9:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
<snip>
> (It still needs a
> mechanism for the number of elements to be determined,
> statically, from the initialization list, in order to be truly
> useful.)
>
I couldn't agree with you more - if only the following was allowed
with initializer lists, references to arrays, and aggregates:
template<class T, int N> std::array<T,N> array(const T (&arr)[N])
{
return arr;
}
auto a = array({1,2,3,4});
regards,
Faisal Vali
Radiation Oncology
Loyola
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <NeverRead@aristeia.com>
Date: Sun, 20 Dec 2009 22:00:33 CST Raw View
Johannes Schaub (litb) wrote:
>
> I believe this can all be done using variadic templates:
>
> template<typename T, size_t S>
> struct array {
> template<typename ...U>
> constexpr array(U&&... u):elems{ u... } { }
>
> T elems[S];
> };
>
> array<int, 3> a = { 1, 2 }; // works, is statically initialized
Alas, this won't work, because you can't deduce a template argument's
type from a brace initializer. The standardizion people have decided
that such a type can be deduced in the context of auto, but not a
template. I have no idea why.
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <NeverRead@aristeia.com>
Date: Sun, 20 Dec 2009 22:02:45 CST Raw View
James Kanze wrote:
>
> That still means you have to write the size. An exception isn't
> as good as a compiler error, and a compiler error isn't as good
> as not having to write the size to begin with.
Perhaps, but I don't see your point, because you have to manually
specify the size of a std::array if you initialize it with a brace
initializer list, regardless.
> What's special is that it can also be initialized statically:
>
> std::array< int, 3 > a = { 1, 2, 3 };
>
> Regardless of where this definition appears, I'm guaranteed that
> it occurs before *any* user defined code, including code in
> constructors of other static objects. In certain cases, that's
> a useful guarantee.
Is this really true? What about the following at namespace scope?
std::array<int, 3> a = { f(), g(), h() };
std::array<int, 3> b = { 1, 2, 3 };
Here's what draft C++0x has to say in 3.6.2/2, which I believe is
where we need to look:
> Objects with static storage duration (3.7.1) or thread storage duration
> (3.7.2) shall be zero-initialized (8.5) before any other initialization
> takes place.
> Constant initialization is performed:
>
> - if each full-expression (including implicit conversions) that appears in
> the initializer of a reference with static or thread storage duration is a
> constant expression (5.19) and the reference is bound to an lvalue
> designating an object with static storage duration or to a temporary (see
> 12.2)
>
> - if an object with static or thread storage duration is initialized such
> that the initialization satisfies the requirements for the object being
> declared with constexpr (7.1.5).
>
> Together, zero-initialization and constant initialization are called static
> initialization; all other initialization is dynamic initialization.
In the code I showed, b isn't a reference, so the first bullet doesn't
apply. b isn't declared constexpr either, so it's not clear to me
that the second bullet applies, either, although the wording is rather
odd. If "the object" were changed to "an object," I'd probably
conclude that b can be statically initialized. With the current
wording, "the object" pretty clearly refers to the object being
initialized, so as things stand now, I don't think that b can be
statically initialized. If not, a would be initialized before b, and
in that case, arbitrary user code would be executed before b were
defined.
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Balog Pal" <pasa@lib.hu>
Date: Mon, 21 Dec 2009 12:00:53 CST Raw View
"Scott Meyers" <NeverRead@aristeia.com>
>> Regardless of where this definition appears, I'm guaranteed that
>> it occurs before *any* user defined code, including code in
>> constructors of other static objects. In certain cases, that's
>> a useful guarantee.
>
> Is this really true? What about the following at namespace scope?
>
> std::array<int, 3> a = { f(), g(), h() };
> std::array<int, 3> b = { 1, 2, 3 };
>
>> - if an object with static or thread storage duration is initialized such
>> that the initialization satisfies the requirements for the object being
>> declared with constexpr (7.1.5).
>>
> In the code I showed, b isn't a reference, so the first bullet doesn't
> apply. b isn't declared constexpr either, so it's not clear to me
> that the second bullet applies, either, although the wording is rather
> odd.
It shall apply. With a fast scan I couldn't locate where it says that
literals count as constexpr, but 7.1.5 p7 has a matching example that
implies.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: CornedBee <wasti.redl@gmx.net>
Date: Mon, 21 Dec 2009 12:01:48 CST Raw View
On Dec 21, 5:02 am, Scott Meyers <NeverR...@aristeia.com> wrote:
>
> > - if an object with static or thread storage duration is initialized such
> > that the initialization satisfies the requirements for the object being
> > declared with constexpr (7.1.5).
>
> b isn't declared constexpr either, so it's not clear to me
> that the second bullet applies, either, although the wording is rather
> odd. If "the object" were changed to "an object," I'd probably
> conclude that b can be statically initialized.
I'm convinced that's the intent. You could reword this as "if an
object ... is initialized such that you could add constexpr to the
declarator and still have a valid initializer". The wording is odd and
hard to understand, but not ambiguous.
Sebastian
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Faisal Vali <faisalv@gmail.com>
Date: Mon, 21 Dec 2009 12:02:07 CST Raw View
On Dec 20, 10:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
> Johannes Schaub (litb) wrote:
>
> > I believe this can all be done using variadic templates:
>
> > template<typename T, size_t S>
> > struct array {
> > template<typename ...U>
> > constexpr array(U&&... u):elems{ u... } { }
>
> > T elems[S];
> > };
>
> > array<int, 3> a = { 1, 2 }; // works, is statically initialized
>
> Alas, this won't work, because you can't deduce a template argument's
> type from a brace initializer. The standardizion people have decided
> that such a type can be deduced in the context of auto, but not a
> template. I have no idea why.
I thought we had established here
http://groups.google.com/group/comp.std.c++/browse_frm/thread/b14c8fad6735a0d9?hl=en#
that it would work.
BTW - I never got a chance to thank the both of you (Johannes Schaub &
Scott Meyers) then for clarifying this issue for me at the time - so
thanks :)
regards,
Faisal Vali
Radiation Oncology
Loyola
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Yechezkel Mett <ymett.on.usenet@gmail.com>
Date: Mon, 21 Dec 2009 12:01:29 CST Raw View
On Dec 21, 6:00 am, Faisal Vali <fais...@gmail.com> wrote:
> On Dec 19, 12:55 am, James Kanze <james.ka...@gmail.com> wrote:
>
> > On Dec 18, 9:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
> <snip>
> > (It still needs a
> > mechanism for the number of elements to be determined,
> > statically, from the initialization list, in order to be truly
> > useful.)
>
> I couldn't agree with you more - if only the following was allowed
> with initializer lists, references to arrays, and aggregates:
>
> template<class T, int N> std::array<T,N> array(const T (&arr)[N])
> {
> return arr;
>
> }
>
> auto a = array({1,2,3,4});
How about
template<class... E>
constexpr
std::array<std::common_type<E...>, sizeof...(E)>
make_array(E... e)
{ return {e...}; }
Yechezkel Mett
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Mon, 21 Dec 2009 19:09:08 CST Raw View
Johannes Schaub (litb) wrote:
> James Kanze wrote:
>
>> On Dec 18, 9:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
>>> In TR1, std::tr1::array needed to be an aggregate so that it
>>> could be brace-initialized. To offer the same capability for
>>> C++0x's std::array, the class could simply declare a
>>> constructor taking a std::initializer_list. So why is
>>> std::array an aggregate? Making it a non-aggregate would
>>> permit e.g., giving it a constructor taking a pair of
>>> iterators.
>>
>> Presumably, so that it can be statically initialized, in order
>> to avoid order of initialization problems.
>>
>
> I believe this can all be done using variadic templates:
>
> template<typename T, size_t S>
> struct array {
> template<typename ...U>
> constexpr array(U&&... u):elems{ u... } { }
>
> T elems[S];
> };
>
Actually, to be a constexpr constructor, all the parameter types must be
taken by value so that they are literal types. But since the goal is static-
initialization, i think this won't matter. One could specialize "array" for
literal types to get back some performance for dynamic initialization cases,
i suspect.
I wonder though about differences in behavior to normal aggregate
initialization - are there any? Thanks!
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Mon, 21 Dec 2009 19:08:54 CST Raw View
Scott Meyers wrote:
> Johannes Schaub (litb) wrote:
>>
>> I believe this can all be done using variadic templates:
>>
>> template<typename T, size_t S>
>> struct array {
>> template<typename ...U>
>> constexpr array(U&&... u):elems{ u... } { }
>>
>> T elems[S];
>> };
>>
>> array<int, 3> a = { 1, 2 }; // works, is statically initialized
>
> Alas, this won't work, because you can't deduce a template argument's
> type from a brace initializer. The standardizion people have decided
> that such a type can be deduced in the context of auto, but not a
> template. I have no idea why.
>
This is not deducing a template argument from a brace initializer. It will
deduce "U" against "1, 2", not against "{ 1, 2 }" (two arguments 1 and 2 are
given to the constructor), if i'm not mistaken.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Mon, 21 Dec 2009 19:09:53 CST Raw View
Scott Meyers wrote:
> Johannes Schaub (litb) wrote:
>>
>> I believe this can all be done using variadic templates:
>>
>> template<typename T, size_t S>
>> struct array {
>> template<typename ...U>
>> constexpr array(U&&... u):elems{ u... } { }
>>
>> T elems[S];
>> };
>>
>> array<int, 3> a = { 1, 2 }; // works, is statically initialized
>
> Alas, this won't work, because you can't deduce a template argument's
> type from a brace initializer. The standardizion people have decided
> that such a type can be deduced in the context of auto, but not a
> template. I have no idea why.
>
I see what i was missing now. an array of aggregates won't work as we need
to do "{ { .... } }" then :/
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <NeverRead@aristeia.com>
Date: Mon, 21 Dec 2009 19:10:30 CST Raw View
Faisal Vali wrote:
> On Dec 20, 10:00 pm, Scott Meyers <NeverR...@aristeia.com> wrote:
>> Johannes Schaub (litb) wrote:
>>
>>> I believe this can all be done using variadic templates:
>>> template<typename T, size_t S>
>>> struct array {
>>> template<typename ...U>
>>> constexpr array(U&&... u):elems{ u... } { }
>>> T elems[S];
>>> };
>>> array<int, 3> a = { 1, 2 }; // works, is statically initialized
>> Alas, this won't work, because you can't deduce a template argument's
>> type from a brace initializer. The standardizion people have decided
>> that such a type can be deduced in the context of auto, but not a
>> template. I have no idea why.
>
>
> I thought we had established here
> http://groups.google.com/group/comp.std.c++/browse_frm/thread/b14c8fad6735a0d9?hl=en#
> that it would work.
Yes, my mistake, I forgot that a templated constructor taking multiple arguments
could be instantiated to match a brace initializer list as long as there is no
constructor taking a std::initializer_list parameter. Thanks for reminding me
of this.
I thus agree that it appears that making std::array a non-aggregate does not
preclude static initialization.
Which brings me back to my question about whether std::array should be defined
to be one.
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Faisal Vali <faisalv@gmail.com>
Date: Tue, 22 Dec 2009 15:48:02 CST Raw View
On Dec 21, 12:01 pm, Yechezkel Mett <ymett.on.use...@gmail.com> wrote:
>
> > On Dec 19, 12:55 am, James Kanze <james.ka...@gmail.com> wrote:
>
> > > (It still needs a
> > > mechanism for the number of elements to be determined,
> > > statically, from the initialization list, in order to be truly
> > > useful.)
<snip>
> How about
>
> template<class... E>
> constexpr
> std::array<std::common_type<E...>, sizeof...(E)>
> make_array(E... e)
> { return {e...}; }
>
Well, if you're willing to use the preprocessor - I believe you can
come even closer to the desired syntax with the following hack:
#define make_array(...) \
std::array<
\
decltype(type_helper(__VA_ARGS__)) \
, sizeof(size_helper(__VA_ARGS__)) \
> __VA_ARGS__; \
/**/
auto a = make_array({1,2,3,4});
And the above relies on the following two functions to work:
1) type_helper is:
template<class T> T type_helper(std::initializer_list<T>);
2) size_helper is slightly more complicated, but is a sequence of
overloads generated
using the BOOST_PP library as follows:
#define PRINT_PARAM(z,n,param) param
#define MAKE_SIZE_HELPERS(z, n, unused) \
struct BOOST_PP_CAT(A,n) { \
template<class T> \
BOOST_PP_CAT(A,n)( \
BOOST_PP_ENUM(n, PRINT_PARAM,T&&) \
);
\
typedef char (&type)[n]; \
}; \
\
BOOST_PP_CAT(A,n)::type \
size_helper(BOOST_PP_CAT(A,n)); \
/**/
BOOST_PP_REPEAT_FROM_TO(1,150,MAKE_SIZE_HELPERS, ~)
#undef PRINT_PARAM
#undef MAKE_SIZE_HELPERS
// The above expands into something along the lines of the following:
struct A1
{
template<class T> A1(T&&);
typedef char (&type)[1];
};
A1::type size_helper(A1);
struct A2
{
template<class T> A2(T&&,T&&);
typedef char (&type)[2];
};
A2::type size_helper(A2);
struct A3 ...
My Preprocessor metaprogramming skills are quite unseasoned, so if
there is a better way to code the above repetition - I would
appreciate any pointers in that direction.
Eitherway, while I do not have a C++0x compiler to check it against,
based on the latest draft (n3000), the above should work.
What do you guys think?
regards,
Faisal Vali
Radiation Oncology
Loyola
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: James Kanze <james.kanze@gmail.com>
Date: Wed, 30 Dec 2009 14:41:16 CST Raw View
On 21 Dec, 04:02, Scott Meyers <NeverR...@aristeia.com> wrote:
> James Kanze wrote:
> > That still means you have to write the size. An exception
> > isn't as good as a compiler error, and a compiler error
> > isn't as good as not having to write the size to begin with.
> Perhaps, but I don't see your point, because you have to
> manually specify the size of a std::array if you initialize it
> with a brace initializer list, regardless.
That's exactly my point. It still only does half the job; with
a C style array, I don't have to specify the size.
> > What's special is that it can also be initialized
> > statically:
> > std::array< int, 3 > a = { 1, 2, 3 };
> > Regardless of where this definition appears, I'm guaranteed
> > that it occurs before *any* user defined code, including
> > code in constructors of other static objects. In certain
> > cases, that's a useful guarantee.
> Is this really true? What about the following at namespace
> scope?
> std::array<int, 3> a = { f(), g(), h() };
> std::array<int, 3> b = { 1, 2, 3 };
It's really true that std::array can be initialized statically.
Of course, if you don't provide static initializers, it won't
be, but that's the case for a C style array as well.
> Here's what draft C++0x has to say in 3.6.2/2, which I believe
> is where we need to look:
> > Objects with static storage duration (3.7.1) or thread
> > storage duration (3.7.2) shall be zero-initialized (8.5)
> > before any other initialization takes place.
> > Constant initialization is performed:
> > - if each full-expression (including implicit conversions)
> > that appears in the initializer of a reference with static
> > or thread storage duration is a constant expression (5.19)
> > and the reference is bound to an lvalue designating an
> > object with static storage duration or to a temporary (see
> > 12.2)
> > - if an object with static or thread storage duration is
> > initialized such that the initialization satisfies the
> > requirements for the object being declared with constexpr
> > (7.1.5).
>
> > Together, zero-initialization and constant initialization
> > are called static initialization; all other initialization
> > is dynamic initialization.
> In the code I showed, b isn't a reference, so the first bullet
> doesn't apply. b isn't declared constexpr either, so it's not
> clear to me that the second bullet applies, either, although
> the wording is rather odd.
I'm not too clear on all of the latest changes in the standard
either. As specified and implemented in the Boost library, the
intent was clearly that static initialization could be used, and
it certainly fulfills the rules for static initialization
according to the definition in the current standard. But I
really doubt that the intent of the second bullet is to restrict
static initialization to objects actually declared constexpr;
that would break an enormous amount of code.
> If "the object" were changed to "an object," I'd probably
> conclude that b can be statically initialized. With the
> current wording, "the object" pretty clearly refers to the
> object being initialized, so as things stand now, I don't
> think that b can be statically initialized. If not, a would
> be initialized before b, and in that case, arbitrary user code
> would be executed before b were defined.
I'm not sure I follow your reasoning. As I read it, the wording
doesn't say that the object must be declared constexpr; it says
that it must meet the requirements for constexpr, i.e. that
declaring it constexpr would be legal.
--
James Kanze
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]