Path: csiph.com!usenet.pasdenom.info!news.albasani.net!.POSTED!not-for-mail From: Andy Lutomirski Newsgroups: comp.std.c++ Subject: Re: Different begin and end types in range-based for Date: Fri, 4 May 2012 14:51:05 -0700 (PDT) Organization: Sonic.Net Lines: 146 Sender: std-cpp-request@vandevoorde.com Approved: stephen.clamage@oracle.com Message-ID: <4FA44847.506@amacapital.net> References: <4fa1a7ad$0$16133$742ec2ed@news.sonic.net> NNTP-Posting-Host: 0JTTNLYSBodTClJenz1TY2gGw+MIgjsV9dgWnDpkhwQ= Content-Type: text/plain; charset=ISO-8859-1 X-Trace: news.albasani.net fMdq+n4a6+3MQ2/doLOUsTdA0BvLKm/Hh/PqyOBg1uupxhTcGo02TGiZfaWz4+C7xjo8YJBW3SlkSJ44A3n9HA== X-Complaints-To: abuse@albasani.net NNTP-Posting-Date: Fri, 4 May 2012 21:51:08 +0000 (UTC) X-Mailer: Perl5 Mail::Internet v2.05 X-Submission-Address: std-cpp-submit@vandevoorde.com Cancel-Lock: sha1:RUzr5IxXH/O81Z59G7lMg8Rm4vY= X-Original-Date: Fri, 04 May 2012 14:21:11 -0700 Xref: csiph.com comp.std.c++:514 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 >> >> 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 ]