Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
| From | Andy Lutomirski<luto@amacapital.net> |
|---|---|
| Newsgroups | comp.std.c++ |
| Subject | Re: Different begin and end types in range-based for |
| Date | 2012-05-04 14:51 -0700 |
| Organization | Sonic.Net |
| Message-ID | <4FA44847.506@amacapital.net> (permalink) |
| References | <4fa1a7ad$0$16133$742ec2ed@news.sonic.net> <jnulb7$4ov$1@dont-email.me> |
On 05/04/2012 11:23 AM, Daniel Krügler wrote:
> Am 03.05.2012 20:10, schrieb Andy Lutomirski:
>> 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.
>
> This issue was discussed before C++11 was released, see below for details.
>
>> 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.)
>
> This issue *was* submitted, this is national body comment GB 27, see
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3296.html
>
> or here:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3289.pdf
>
> At that time the range-for-loop was intensively discussed and no
> consensus was found for this change. One further reason for not applying
> this change was because the library algorithms also use a homogeneous
> iterator model and the same applied to the concept models that were
> considered just before.
>
> Now, after the dust has settled and real implementations do exist, there
> might be a good time to consider an extension of the current rules. If
> you are interested in this I suggest to work on a proposal for that new
> feature.
How do I go about submitting a proposal like that?
This idea is made a bit uglier by the fact (that I mis-remebered) that
begin(__range) and end(__range) are tried after .begin() and .end(). I
had imagined a container that implemented C++98-style .begin() and
.end() but had non-member begin and end that used different types and
were more efficient.
This can add to my fun as I masochistically try to maintain a decently
large code base in a language that just got standardized using compilers
that are a little bit behind :)
--Andy
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to comp.std.c++ | Previous | Next — Previous in thread | Next in thread | Find similar
Different begin and end types in range-based for Andy Lutomirski <luto@amacapital.net> - 2012-05-03 11:10 -0700
Re: Different begin and end types in range-based for Daniel Krügler<daniel.kruegler@googlemail.com> - 2012-05-04 11:23 -0700
Re: Different begin and end types in range-based for Andy Lutomirski<luto@amacapital.net> - 2012-05-04 14:51 -0700
Re: Different begin and end types in range-based for Andy Lutomirski <luto@amacapital.net> - 2012-05-04 23:01 -0700
csiph-web