Re: initializer_list members not being constexpr anymore
On 29 Jun., 22:24, Rodolfo Lima <rodo...@rodsoft.org> wrote:
Hi, as seen in the last C++0x standard draft, initializer_list's
begin/end/size aren't constexpr anymore. What is the rationale for
that? The returned values are known at compile time, I don't see
why they cannot be constexpr.
First, "anymore" implies that at some point of time the
standard draft did contain these functions with a
constexpr specifier - but this never had been the case,
because the first accepted proposal paper
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm
added to
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf
did not suggest them. Nevertheless, it is correct, that the
first initializer list papers (e.g. n1919, n2100, ...)
did consider such a specification, but those papers also
mentioned some problems with this idea. They came to
the conclusion that if we consider std::initializer_list
objects as intrinsic types this could somehow be realized
via a special rule solely valid for this intrinsic.
As of the current definition of constexpr functions
and as of the current specification of the initialization
of a std::initializer_list object, this could *not*
be handled by the "normal" language rules. Additionally
it would lead to some severe constraints when the
functions could be used as constexpr functions. To
explain why, lets consider a possible std::initializer_list
implementation that attempts to do the best to realize
that. The definition we could try could be as
follows (ignoring typedefs, includes, etc.):
namespace std {
template<class E> class initializer_list {
const E* beg;
size_t sz;
public:
constexpr initializer_list(const E* beg, size_t sz) : beg(beg),
sz(sz) {}
constexpr size_t size() { return sz; }
[..]
};
}
Now this would make the following program well-formed:
#include <initializer_list>
constexpr std::initializer_list<int> li = {0, 42};
constexpr int sz = li.size();
int main() {}
but this slightly modified program wouldn't be:
#include <initializer_list>
int main() {
constexpr std::initializer_list<int> li = {0, 42};
constexpr int sz = li.size();
}
The reason is, that in the second example the current
specification of the initialization of a std::initializer_list
object (see 8.5.4 [dcl.init.list]/4 in the FCD) meets a
constraint of constant expressions (see 5.19 [expr.const]/2):
"A conditional-expression is a constant expression unless
it involves one of the following as a potentially evaluated
subexpression [..]
? an array-to-pointer conversion (4.2) that is applied to
a glvalue that does not designate an object with static
storage duration; [..]
"
This constraint is not satisfied for the second example
and thus the initialization of the local li object
would be ill-formed (even though the size of that
array could still be evaluated as a constant expression).
This means that by normal FCD language rules, users
could only benefit from constexpr functions of
std::initializer_list, if this is an object of static
storage duration - I consider this as a very rare
case.
As indicated above, it would still be possible to
get away language restrictions for an compiler-
intrinsic type as std::initializer_list and just
*require* that size() is supposed to be a constexpr
function. This is probably possible, but at this
point in time
a) it would enforce *all* implementations to realize
this (This is not as simple as it looks - even the
decimal type specification as of
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2849.pdf
does not require decimals to be represented as
compiler-intrinsic types).
b) it is currently unknown whether the effort
required for this specification is justified.
It is probably wiser to wait and to see how
implementations can handle this over the first
time and to possibly consider a stronger
requirement in the future.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]