Re: initializer_list members not being constexpr anymore
Hi Daniel, first of all, thanks for your throughout explanation.
On 1 jul, 11:49, Daniel Kr?gler <daniel.krueg...@googlemail.com> >
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
Sure, my bad.
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
I'm aware of the difficulties involved, but didn't know about the
constraints you've mentioned. They would indeed make constexpr
initializer_list<E>::size next to useless.
I wonder (maybe na?vely), if initializer_list could be something like
this:
template <class E, size_t N=numeric_limits<size_t>::max()>
class initializer_list
{
const E *m_array;
public:
initializer_list(const E *a) : m_array(a) {}
const E *begin() const { return m_array; }
const E *end() const { return begin() + size(); }
constexpr size_t size() const { return N; }
};
template <class E>
class initializer_list<E, numeric_limits<size_t>::max()>
{
const E *m_array;
size_t m_size;
public:
initializer_list(const E *a, size_t s)
: m_array(a), m_size(s) {}
const E *begin() const { return m_array; }
const E *end() const { return begin() + size(); }
size_t size() const { return m_size; }
};
So, whenever the compiler must convert a list into a
initializer_list<E>, it would do as it currently does, according to
FCD. But, to convert to a initializer_list<E,N>, the list must have
exactly N items (or if N is a template argument to be deduced, N would
be deduced to the number of list items).
An valid use case is the following: suppose I'm creating a vector/
matrix class whose dimensions are known at compile time. So I would
have (except for any typos, includes, ...):
//----------------------------------------
using namespace std;
template <class T, int N>
class Vector
{
public:
Vector(T v)
{
fill(m_data, m_data+N, v);
}
Vector(const initializer_list<T,N> &cols)
{
copy(cols.begin(), cols.end(), m_data);
}
T &operator[](int j) { return m_data[j]; }
const T &operator[](int j) const { return m_data[j]; }
private:
T m_data[N];
};
template <class T, int M, int N>
class Matrix
{
public:
Matrix(T v)
{
for(int i=0; i<M; ++i)
for(int j=0; j<N; ++j)
m_data[i][j] = i==j ? v : 0;
}
Matrix(const initializer_list<Vector<T,N>, M> &rows)
{
copy(rows.begin(), rows.end(), m_data);
}
Vector<T,N> &operator[](int i) { return m_data[i]; }
const Vector<T,N> &operator[](int i) const { return m_data[i]; }
private:
Vector<T,N> m_data[M];
};
template <class T, int M, int N>
auto create_matrix(const std::initializer_list<Vector<T,N>,M> &rows)
-> Matrix<T,M,N>
{
return Matrix<T,M,N>(rows);
}
Matrix<int,2,2> m1{{1,2},{3,4}};
auto m2 = create_matrix({1,2},{3,4});
assert(m1 == m2); // supposing there is a Matrix::operator==
//----------------------------------------
For vectors I can create a variadic template constructor and
statically assert its size to be equal to N, the call to Vector<T,
1>{1} would end up calling the "wrong" constructor (the first), but
with the same semantics of the second.
But I can't do the same with Matrix, since the variadic parameters
would be deduced to be std::initializer_list, which is invalid
according to FCD's 14.9.2.5 [temp.deduct.type]/5 paragraph, so I have
to resort to runtime size checking, which is sad.
Regards,
Rodolfo Lima.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]