I'm not sure whether this is should be submitted as a DR or if I should
just live with it, but it would be convenient to have more flexibility
in implementing containers with range-based for.
6.5.4 [stmt.ranged] defines this statement:
for ( for-range-declaration : expression ) statement
as equivalent to:
{
auto && __range = digits();
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
auto i = *__begin;
statement
}
}
There is nothing in this definition that fundamentally requires that
__begin and __end have the same type. However, 7.1.6.4 [dcl.spec.auto]
says:
7. If the list of declarators contains more than one declarator, the
type of each declared variable is determined
as described above. If the type deduced for the template parameter U is
not the same in each deduction, the
program is ill-formed.
Therefore, if the return types of begin-expr and end-expr are different,
the program is ill-formed. An alternative formulation that would be
identical other than this restriction (as far as I can tell) would be:
{
auto && __range = digits();
auto __begin = begin-expr;
auto __end = end-expr;
for ( ;
__begin != __end;
++__begin ) {
auto i = *__begin;
statement
}
}
For example:
#include <iostream>
struct digit_end {};
struct digit_iter
{
int i;
void operator ++ () { ++i; }
int operator * () const { return i; }
bool operator != (digit_end) const { return i != 10; }
};
struct digits
{
digit_iter begin() const { digit_iter it; it.i = 0; return it; }
digit_end end() const { return digit_end(); }
};
int main(int, char **)
{
using namespace std;
// for (auto i : digits()) cout << i << endl; [ill-formed]
// Alternative formulation, which works in g++ 4.6
{
auto && __range = digits();
auto __begin = begin(__range);
auto __end = end(__range);
for ( ;
__begin != __end;
++__begin ) {
auto i = *__begin;
cout << i << endl;
}
}
return 0;
}
It seems to me that 6.5.4 [stmt.ranged] should either be changed to
allow this use or should contain an example or explanatory note
indicating that this use is explicitly disallowed.
This particular example is silly, but I have a container in real code
for which there is no efficient way to implement a true end() function,
but checking whether at iterator is at the end is very simple.
(This idea is not new. The same issue is mentioned in
http://cxxpanel.org.uk/ballotcomment/526 but AFAICT was never submitted
anywhere.)
Thanks,
Andy
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:
std-cpp...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ:
http://www.comeaucomputing.com/csc/faq.html ]