[clang++][c++11] complier problems about "ranged-based for"

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[clang++][c++11] complier problems about "ranged-based for"

ZhangXiongpang
This post was updated on .
Platform: linux, x86_64, clang++3.2

6.5.4/p1:
------------------------------------------------------------
In each case, a range-based for statement is equivalent to
  {
      auto && __range = range-init;
      for ( auto __begin = begin-expr,
            __end = end-expr;
            __begin != __end;
            ++__begin ) {
          for-range-declaration = *__begin;
          statement
      }
  }
------------------------------------------------------------
The begin-expr and end-expr have two cases if _RangeT is not an array type:
(1) begin-expr and end-expr are __range.begin() and __range.end(), respectively
(2) begin-expr and end-expr are begin(__range) and end(__range), respectively
Standard doesn't say whether "begin" and "end" must be an function, so I think they can also be function objects or class names. Then I wrote three tests, first two compiled failed, last one compiled ok. Maybe clang++ shall support the first two cases.

Example 1:
------------------------------------------------------------
struct X {};
struct Iterator {
    Iterator(int v) : value(v) {}
    Iterator& operator++(){ ++value; return *this; }
    int& operator*(){ return value; }
    bool operator!=(const Iterator& iter) { return value != iter.value; }
    int value;
};
struct Functor {
    Functor(int v) : value(v) {}
    Iterator operator()(const X&) { return Iterator(value); }
    int value;
};

Functor begin(1), end(5);

int main() {
    X x;
    auto&& __range = x; // ok
    for ( auto __begin = begin(__range), __end = end(__range);
          __begin != __end; ++__begin ) {
        int i = *__begin;
        // ...
    } // ok
    for (int i : x) ; // error: no viable 'begin' function available
}
------------------------------------------------------------


Example 2:
------------------------------------------------------------
int count = 0;
struct X {};
struct Y {
    Y(const X&) { value = ++count; }
    Y(const Y&) { value = ++count; }
    Iterator& operator++(){ ++value; return *this; }
    int& operator*() { return value; }
    bool operator != (const Y& y) { return value != y.value; }
    int value;
};

typedef Y begin;
typedef Y end;

int main() {
    X x;
    auto&& __range = x; // ok
    for ( auto __begin = begin(__range), __end = end(__range);
          __begin != __end; ++__begin ) {
        int i = *__begin;
        // ...
    } // ok
    for (int i : x) ; // error: no viable 'begin' function available
}
------------------------------------------------------------


Example 3:
------------------------------------------------------------
struct Iterator {
    Iterator(int v) : value(v) {}
    int& operator++(){ return ++value; }
    int& operator*(){ return value; }
    bool operator!=(const Iterator& iter) { return value != iter.value; }
    int value;
};

struct X {
    struct Functor {
        Functor(int v) : value(v) {}
        Iterator operator()() { return Iterator(value); }
        int value;
    };
    Functor begin, end;
    X() : begin(1), end(5) {}
};

int main() {
    X x;
    auto&& __range = x; // ok
    for ( auto __begin = __range.begin(), __end = __range.end();
          __begin != __end; ++__begin ) {
        int i = *__begin;
        // ...
    } // ok
    for (int i : x) ; // ok, very good!
}
------------------------------------------------------------
Reply | Threaded
Open this post in threaded view
|

Re: [clang++][c++11] complier problems about "ranged-based for"

James Dennett
On Thu, Mar 7, 2013 at 11:28 PM, ZhangXiongpang
<[hidden email]> wrote:

> Platform: linux, x86_64, clang++3.2
>
> 6.5.4/p1:
> ------------------------------------------------------------
> In each case, a range-based for statement is equivalent to
>   {
>       auto && __range = range-init;
>       for ( auto __begin = begin-expr,
>             __end = end-expr;
>             __begin != __end;
>             ++__begin ) {
>           for-range-declaration = *__begin;
>           statement
>       }
>   }
> ------------------------------------------------------------
> The begin-expr and end-expr have two cases if _RangeT is not an array type:
> (1) begin-expr and end-expr are __range.begin() and __range.end(),
> respectively
> (2) begin-expr and end-expr are begin(__range) and end(__range),
> respectively
> Standard doesn't say whether "begin" and "end" must be an function, so I
> think they can also be function objects or class names.

I think that the Standard is clear on this (well, as clear as it ever
is), and that Clang appears to implement this correctly.

In case (1), where "begin" and "end" are looked up as class members,
C++ doesn't allow the syntax object.TypeName, so the only interesting
case is your example 3, where range.begin and range.end are callable
data members.  As your tests show, Clang permits that.

In case (2), "begin" and "end" are found via argument-dependent
lookup, which only finds function (and function template) names.  You
can add "using std::begin; using std::end;" inside your functions that
emulate range-based "for" to prevent finding the globals via non-ADL
lookup and more accurately emulate the semantics of range-based for
(and hence will not compile).

-- James
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [clang++][c++11] complier problems about "ranged-based for"

ZhangXiongpang
This post was updated on .
James Dennett wrote
> In case (1), where "begin" and "end" are looked up as class members,
> C++ doesn't allow the syntax object.TypeName,
I know C++ doesn't allow the syntax "object.TypeName",
but the "object"(__begin) is a function object,
it is also callable. so why not treat the object as a function?

James Dennett wrote
> In case (2), "begin" and "end" are found via argument-dependent
> lookup, which only finds function (and function template) names.
I'm confused that if standard only permit implement to find function,
why not explicitly saying that "begin" and "end" shall be functions?
Reply | Threaded
Open this post in threaded view
|

Re: [clang++][c++11] complier problems about "ranged-based for"

James Dennett
On Fri, Mar 8, 2013 at 2:32 AM, ZhangXiongpang <[hidden email]> wrote:
> James Dennett wrote
>>> In case (1), where "begin" and "end" are looked up as class members,
>>> C++ doesn't allow the syntax object.TypeName,
>
> I know C++ doesn't allow the syntax "object.TypeName",
> but the "object"(__begin) is a also a function object,
> it is callable. so why not treat the object as a function?

I'm sorry, I don't understand your question.  Are you talking about
the case of your test (3), which compiles successfully (as it should),
or something else?

> James Dennett wrote
>>> In case (2), "begin" and "end" are found via argument-dependent
>>> lookup, which only finds function (and function template) names.
>
> I'm confused that if standard only permit implement to find function,
> why not explicitly saying that "begin" and "end" shall be functions?

Because it doesn't need to.  The Standard is not a tutorial, and tries
to avoid redundancy.

-- James
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [clang++][c++11] complier problems about "ranged-based for"

ZhangXiongpang
This post was updated on .
James Dennett wrote
On Fri, Mar 8, 2013 at 2:32 AM, ZhangXiongpang <[hidden email]> wrote:
> James Dennett wrote
>>> In case (1), where "begin" and "end" are looked up as class members,
>>> C++ doesn't allow the syntax object.TypeName,
>
> I know C++ doesn't allow the syntax "object.TypeName",
> but the "object"(__begin) is a also a function object,
> it is callable. so why not treat the object as a function?

I'm sorry, I don't understand your question.  Are you talking about
the case of your test (3), which compiles successfully (as it should),
or something else?
I mean in example 1 "begin" and "end" are also callable, just like the "begin" and "end" in example 3. The difference between example 1 and example 3 is:
(1) in example 3, there is a member who named "begin" in class X, so it will look up "x.begin()" and "x.end()", standard says "begin-expr and end-expr are __range.begin() and __range.end(), respectively".
(2) in example 1, no member named "begin" or "end" in class X, so it will look up "begin(x)" from the associated namespace of x, standard says "begin-expr and end-expr are begin(__range) and end(__range), respectively".


Reply | Threaded
Open this post in threaded view
|

Re: [clang++][c++11] complier problems about "ranged-based for"

James Dennett
On Fri, Mar 8, 2013 at 2:37 PM, ZhangXiongpang <[hidden email]> wrote:

> James Dennett wrote
>> On Fri, Mar 8, 2013 at 2:32 AM, ZhangXiongpang &lt;
>
>> zhangxiongpang@
>
>> &gt; wrote:
>>> James Dennett wrote
>>>>> In case (1), where "begin" and "end" are looked up as class members,
>>>>> C++ doesn't allow the syntax object.TypeName,
>>>
>>> I know C++ doesn't allow the syntax "object.TypeName",
>>> but the "object"(__begin) is a also a function object,
>>> it is callable. so why not treat the object as a function?
>>
>> I'm sorry, I don't understand your question.  Are you talking about
>> the case of your test (3), which compiles successfully (as it should),
>> or something else?
>
> I mean in example 1 "begin" and "end" are also callable, just like the
> "begin" and "end" in example 3. The difference between example 1 and example
> 3 is:
> (1) in example 3, there is a member who named "begin" in class X, so it will
> look up "x.begin()" and "x.end()", standard says "begin-expr and end-expr
> are __range.begin() and __range.end(), respectively".

Right, this is why (3) compiles.

> (2) in example 1, no member named "begin" or "end" in class X, so it will
> look up "begin(x)" from the associated namespace of x, standard syas
> "begin-expr and end-expr are begin(__range) and end(__range), respectively".

The standard says that the lookup for name names "begin" and "end" is
ADL in the non-member case, and so the non-functions begin and end are
not found, and the code is erroneous.

Here's a modified example showing that the hand-written loop fails in
the same way if restricted to using ADL + namespace std.

struct X {};
struct Iterator {
    Iterator(int v) : value(v) {}
    int operator++(){ return ++value; }
    int& operator*(){ return value; }
    bool operator!=(const Iterator& iter) { return value != iter.value; }
    int value;
};
struct Functor {
    Functor(int v) : value(v) {}
    Iterator operator()(const X&) { return Iterator(value); }
    int value;
};

Functor begin(1), end(5);

namespace std {
int *begin(int*);
int *end(int*);
}

int main() {
  using std::begin;
  using std::end;

    X x;
    auto&& __range = x; // ok
    for ( auto __begin = begin(__range),  // error: no matching
function for call to 'begin'
          __end = end(__range);
          __begin != __end; ++__begin ) {
        int i = *__begin;
        // ...
    } // ok
    for (int i : x) ; *// error: no viable 'begin' function available*
}

Note that the manually lowered loop fails to compile, for the same
reason as the range-based one: no suitable "begin" is found.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [clang++][c++11] complier problems about "ranged-based for"

ZhangXiongpang
James Dennett wrote
On Fri, Mar 8, 2013 at 2:37 PM, ZhangXiongpang <[hidden email]> wrote:
> James Dennett wrote
>> On Fri, Mar 8, 2013 at 2:32 AM, ZhangXiongpang <
>
>> zhangxiongpang@
>
>> > wrote:
>>> James Dennett wrote
>>>>> In case (1), where "begin" and "end" are looked up as class members,
>>>>> C++ doesn't allow the syntax object.TypeName,
>>>
>>> I know C++ doesn't allow the syntax "object.TypeName",
>>> but the "object"(__begin) is a also a function object,
>>> it is callable. so why not treat the object as a function?
>>
>> I'm sorry, I don't understand your question.  Are you talking about
>> the case of your test (3), which compiles successfully (as it should),
>> or something else?
>
> I mean in example 1 "begin" and "end" are also callable, just like the
> "begin" and "end" in example 3. The difference between example 1 and example
> 3 is:
> (1) in example 3, there is a member who named "begin" in class X, so it will
> look up "x.begin()" and "x.end()", standard says "begin-expr and end-expr
> are __range.begin() and __range.end(), respectively".

Right, this is why (3) compiles.

> (2) in example 1, no member named "begin" or "end" in class X, so it will
> look up "begin(x)" from the associated namespace of x, standard syas
> "begin-expr and end-expr are begin(__range) and end(__range), respectively".

The standard says that the lookup for name names "begin" and "end" is
ADL in the non-member case, and so the non-functions begin and end are
not found, and the code is erroneous.

Here's a modified example showing that the hand-written loop fails in
the same way if restricted to using ADL + namespace std.

struct X {};
struct Iterator {
    Iterator(int v) : value(v) {}
    int operator++(){ return ++value; }
    int& operator*(){ return value; }
    bool operator!=(const Iterator& iter) { return value != iter.value; }
    int value;
};
struct Functor {
    Functor(int v) : value(v) {}
    Iterator operator()(const X&) { return Iterator(value); }
    int value;
};

Functor begin(1), end(5);

namespace std {
int *begin(int*);
int *end(int*);
}

int main() {
  using std::begin;
  using std::end;

    X x;
    auto&& __range = x; // ok
    for ( auto __begin = begin(__range),  // error: no matching
function for call to 'begin'
          __end = end(__range);
          __begin != __end; ++__begin ) {
        int i = *__begin;
        // ...
    } // ok
    for (int i : x) ; *// error: no viable 'begin' function available*
}

Note that the manually lowered loop fails to compile, for the same
reason as the range-based one: no suitable "begin" is found.
I understand. Thanks very much for you answer.