Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.std.c++ > #515

Re: Different begin and end types in range-based for

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 23:01 -0700
Organization Sonic.Net
Message-ID <4FA44CD3.30502@amacapital.net> (permalink)
References <4fa1a7ad$0$16133$742ec2ed@news.sonic.net> <jnulb7$4ov$1@dont-email.me>

Show all headers | View raw


[Apologies if this is a duplicate.  My mail client messed up on the
first try.]

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 | NextPrevious in thread | Find similar


Thread

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