Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #70956 > unrolled thread
| Started by | Ralf Goertz <me@myprovider.invalid> |
|---|---|
| First post | 2020-01-02 10:37 +0100 |
| Last post | 2020-01-05 19:55 +0000 |
| Articles | 13 — 7 participants |
Back to article view | Back to comp.lang.c++
std::copy with std::ostream_iterator<std::array...> Ralf Goertz <me@myprovider.invalid> - 2020-01-02 10:37 +0100
Re: std::copy with std::ostream_iterator<std::array...> Paavo Helde <myfirstname@osa.pri.ee> - 2020-01-02 12:27 +0200
Re: std::copy with std::ostream_iterator<std::array...> Bo Persson <bo@bo-persson.se> - 2020-01-02 12:26 +0100
Re: std::copy with std::ostream_iterator<std::array...> Ralf Goertz <me@myprovider.invalid> - 2020-01-02 16:10 +0100
Re: std::copy with std::ostream_iterator<std::array...> James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-01-02 23:13 -0500
Re: std::copy with std::ostream_iterator<std::array...> Ralf Goertz <me@myprovider.invalid> - 2020-01-03 07:49 +0100
Re: std::copy with std::ostream_iterator<std::array...> James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-01-03 08:30 -0500
Re: std::copy with std::ostream_iterator<std::array...> Bo Persson <bo@bo-persson.se> - 2020-01-03 15:09 +0100
Re: std::copy with std::ostream_iterator<std::array...> Ike Naar <ike@sdf.lonestar.org> - 2020-01-04 21:46 +0000
Re: std::copy with std::ostream_iterator<std::array...> Ralf Goertz <me@myprovider.invalid> - 2020-01-05 16:06 +0100
Re: std::copy with std::ostream_iterator<std::array...> Jorgen Grahn <grahn+nntp@snipabacken.se> - 2020-01-05 18:24 +0000
Re: std::copy with std::ostream_iterator<std::array...> Öö Tiib <ootiib@hot.ee> - 2020-01-05 10:56 -0800
Re: std::copy with std::ostream_iterator<std::array...> Jorgen Grahn <grahn+nntp@snipabacken.se> - 2020-01-05 19:55 +0000
| From | Ralf Goertz <me@myprovider.invalid> |
|---|---|
| Date | 2020-01-02 10:37 +0100 |
| Subject | std::copy with std::ostream_iterator<std::array...> |
| Message-ID | <qukdjv$fco$1@dont-email.me> |
Hi,
I don't get the problem in the following program. If I use
using Coords=Foo;
everything is okay but with
using Coords=std::array<int,2>
I get bombarded with (for me) undecipherable template errors originating
from the std::copy line. Note that without that line it works for both
types, so the operator overload "<<" should not be the problem.
What ist going on
#include <iostream>
#include <iterator>
#include <algorithm>
#include <array>
#include <set>
struct Foo {
int i,j;
bool operator<(const struct Foo &r) const { //needed for set
if (i<r.i) return true;
return j<r.j;
}
};
std::ostream & operator<<(std::ostream &o,const std::array<int,2> &c) {
return o<<'('<<c[0]<<','<<c[1]<<')';
}
std::ostream & operator<<(std::ostream &o,const Foo &c) {
return o<<'('<<c.i<<','<<c.j<<')';
}
using Coords=Foo; //this works
//using Coords=std::array<int,2>; //this doesn't
int main() {
std::set<Coords> ls;
ls.insert(Coords({47,11}));
std::cout<<*ls.begin()<<std::endl;
std::copy(ls.cbegin(),ls.cend(),std::ostream_iterator<Coords>(std::cout," ")); //Compile error with array
std::cout<<"\n";
}
[toc] | [next] | [standalone]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2020-01-02 12:27 +0200 |
| Message-ID | <qukgic$589$1@dont-email.me> |
| In reply to | #70956 |
On 2.01.2020 11:37, Ralf Goertz wrote: > Hi, > > I don't get the problem in the following program. If I use > > using Coords=Foo; > > everything is okay but with > > using Coords=std::array<int,2> > > I get bombarded with (for me) undecipherable template errors originating > from the std::copy line. Note that without that line it works for both > types, so the operator overload "<<" should not be the problem. Your example starts to compile if you put the relevant operator<< inside namespace std.
[toc] | [prev] | [next] | [standalone]
| From | Bo Persson <bo@bo-persson.se> |
|---|---|
| Date | 2020-01-02 12:26 +0100 |
| Message-ID | <h762c4FgmbdU1@mid.individual.net> |
| In reply to | #70956 |
On 2020-01-02 at 10:37, Ralf Goertz wrote:
> Hi,
>
> I don't get the problem in the following program. If I use
>
> using Coords=Foo;
>
> everything is okay but with
>
> using Coords=std::array<int,2>
>
> I get bombarded with (for me) undecipherable template errors originating
> from the std::copy line. Note that without that line it works for both
> types, so the operator overload "<<" should not be the problem.
But it is. :-)
Argument dependent lookup will search for an operator in the
namespace(s) of the arguments (thus its name :-).
If you (or a standard algorithm) use an operator<< with two types from
namespace std (for example, std::ostream and std::array), the compiler
will look for an operator<< also in namespace std. There are lots of
them, but none for std::array.
Your operator is in the global namespace, but std::array is not. So that
operator will not be found.
It works for Foo, because the type and the operator are in the same
namespace.
>
> What ist going on
>
> #include <iostream>
> #include <iterator>
> #include <algorithm>
> #include <array>
> #include <set>
>
> struct Foo {
> int i,j;
> bool operator<(const struct Foo &r) const { //needed for set
> if (i<r.i) return true;
> return j<r.j;
> }
> };
>
> std::ostream & operator<<(std::ostream &o,const std::array<int,2> &c) {
> return o<<'('<<c[0]<<','<<c[1]<<')';
> }
>
> std::ostream & operator<<(std::ostream &o,const Foo &c) {
> return o<<'('<<c.i<<','<<c.j<<')';
> }
>
> using Coords=Foo; //this works
> //using Coords=std::array<int,2>; //this doesn't
>
> int main() {
> std::set<Coords> ls;
> ls.insert(Coords({47,11}));
> std::cout<<*ls.begin()<<std::endl;
> std::copy(ls.cbegin(),ls.cend(),std::ostream_iterator<Coords>(std::cout," ")); //Compile error with array
> std::cout<<"\n";
> }
>
[toc] | [prev] | [next] | [standalone]
| From | Ralf Goertz <me@myprovider.invalid> |
|---|---|
| Date | 2020-01-02 16:10 +0100 |
| Message-ID | <qul14t$msl$1@dont-email.me> |
| In reply to | #70964 |
Am Thu, 2 Jan 2020 12:26:59 +0100 schrieb Bo Persson <bo@bo-persson.se>: > On 2020-01-02 at 10:37, Ralf Goertz wrote: > > Hi, > > > > I don't get the problem in the following program. If I use > > > > using Coords=Foo; > > > > everything is okay but with > > > > using Coords=std::array<int,2> > > > > I get bombarded with (for me) undecipherable template errors > > originating from the std::copy line. Note that without that line it > > works for both types, so the operator overload "<<" should not be > > the problem. > > But it is. :-) > > Argument dependent lookup will search for an operator in the > namespace(s) of the arguments (thus its name :-). > > If you (or a standard algorithm) use an operator<< with two types > from namespace std (for example, std::ostream and std::array), the > compiler will look for an operator<< also in namespace std. There are > lots of them, but none for std::array. > > Your operator is in the global namespace, but std::array is not. So > that operator will not be found. > > It works for Foo, because the type and the operator are in the same > namespace. Thanks for the explanation. I figured as much after having read Paavo's reply. But two questions remain. First, I thought it would be illegal (or at least frowned upon) for user code to inject anything into the std namespace. And what is the difference for the line std::cout<<*ls.begin()<<std::endl; (ls being of type std::set<std::array<int,2>>) although I have defined the operator in the global namespace and both operands are in std (I guess). Shouldn't the rule you quoted also lead to a lookup failure?
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2020-01-02 23:13 -0500 |
| Message-ID | <qumf12$jee$1@dont-email.me> |
| In reply to | #70971 |
On 1/2/20 10:10 AM, Ralf Goertz wrote: ... > reply. But two questions remain. First, I thought it would be illegal > (or at least frowned upon) for user code to inject anything into the std > namespace. "A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited." (17.6.4.2.1p1) "A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template." (17.6.4.2.1p2).
[toc] | [prev] | [next] | [standalone]
| From | Ralf Goertz <me@myprovider.invalid> |
|---|---|
| Date | 2020-01-03 07:49 +0100 |
| Message-ID | <qumo6m$kan$1@dont-email.me> |
| In reply to | #70995 |
Am Thu, 2 Jan 2020 23:13:22 -0500 schrieb James Kuyper <jameskuyper@alumni.caltech.edu>: > On 1/2/20 10:10 AM, Ralf Goertz wrote: > ... > > reply. But two questions remain. First, I thought it would be > > illegal (or at least frowned upon) for user code to inject anything > > into the std namespace. > > "A program may add a template specialization for any standard library > template to namespace std only if the declaration depends on a > user-defined type and the specialization meets the standard library > requirements for the original template and is not explicitly > prohibited." (17.6.4.2.1p1) > "A program may explicitly instantiate a template defined in the > standard library only if the declaration depends on the name of a > user-defined type and the instantiation meets the standard library > requirements for the original template." (17.6.4.2.1p2). Thanks. Do you also have an answer to the second question: std::cout<<*ls.begin()<<std::endl; std::copy(ls.begin(),ls.end(),std::ostream_iterator<Coords>(std::cout," ")); Why doesn't the first of the above lines require the operator << to be defined in std whereas the second does?
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2020-01-03 08:30 -0500 |
| Message-ID | <qunfls$gce$3@dont-email.me> |
| In reply to | #70999 |
On 1/3/20 1:49 AM, Ralf Goertz wrote: ... > Thanks. Do you also have an answer to the second question: No - answering that question would require more time than I can afford to spend right now. I hope someone else answers it first. > > std::cout<<*ls.begin()<<std::endl; > std::copy(ls.begin(),ls.end(),std::ostream_iterator<Coords>(std::cout," ")); > > Why doesn't the first of the above lines require the operator << to be > defined in std whereas the second does? >
[toc] | [prev] | [next] | [standalone]
| From | Bo Persson <bo@bo-persson.se> |
|---|---|
| Date | 2020-01-03 15:09 +0100 |
| Message-ID | <h79092F4t0jU1@mid.individual.net> |
| In reply to | #70971 |
On 2020-01-02 at 16:10, Ralf Goertz wrote:
> Am Thu, 2 Jan 2020 12:26:59 +0100
> schrieb Bo Persson <bo@bo-persson.se>:
>
>> On 2020-01-02 at 10:37, Ralf Goertz wrote:
>>> Hi,
>>>
>>> I don't get the problem in the following program. If I use
>>>
>>> using Coords=Foo;
>>>
>>> everything is okay but with
>>>
>>> using Coords=std::array<int,2>
>>>
>>> I get bombarded with (for me) undecipherable template errors
>>> originating from the std::copy line. Note that without that line it
>>> works for both types, so the operator overload "<<" should not be
>>> the problem.
>>
>> But it is. :-)
>>
>> Argument dependent lookup will search for an operator in the
>> namespace(s) of the arguments (thus its name :-).
>>
>> If you (or a standard algorithm) use an operator<< with two types
>> from namespace std (for example, std::ostream and std::array), the
>> compiler will look for an operator<< also in namespace std. There are
>> lots of them, but none for std::array.
>>
>> Your operator is in the global namespace, but std::array is not. So
>> that operator will not be found.
>>
>> It works for Foo, because the type and the operator are in the same
>> namespace.
>
> Thanks for the explanation. I figured as much after having read Paavo's
> reply. But two questions remain. First, I thought it would be illegal
> (or at least frowned upon) for user code to inject anything into the std
> namespace. And what is the difference for the line
>
> std::cout<<*ls.begin()<<std::endl;
>
> (ls being of type std::set<std::array<int,2>>) although I have defined
> the operator in the global namespace and both operands are in std (I
> guess). Shouldn't the rule you quoted also lead to a lookup failure?
>
Yes, but there are more rules (lots of them)...
The compiler also does an Unqualified name lookup
https://en.cppreference.com/w/cpp/language/unqualified_lookup
(about 10 pages of rules) for "<< *ls.begin" and finds the global one
from main(), because the call is done from the global namespace.
The code for std::copy is inside namespace std so the search for an
operator starts there. And it finds lots of operator<< in the namespace,
so it stops there:
"For an unqualified name, that is a name that does not appear to the
right of a scope resolution operator ::, name lookup examines the scopes
as described below, until it finds at least one declaration of any kind,
at which time the lookup stops and no further scopes are examined."
And then the compiler performs an overload resolution (another 30 pages
in the standard) for the names it has found.
The complete process is *way* too complicated to fully describe in a
post here, so the recommendation is to always declare the operators in
the same namespace as (at least one of) the operands, and avoid most of
the complications.
Bo Persson
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@sdf.lonestar.org> |
|---|---|
| Date | 2020-01-04 21:46 +0000 |
| Message-ID | <slrn3flsr121tl.4k8.ike@sdf.lonestar.org> |
| In reply to | #70956 |
On 2020-01-02, Ralf Goertz <me@myprovider.invalid> wrote:
> struct Foo {
> int i,j;
> bool operator<(const struct Foo &r) const { //needed for set
> if (i<r.i) return true;
> return j<r.j;
This looks suspect.
Do you want (2,1) to be less than (1,2) ?
if you want to define a lexicographical order on (i,j), the comparison should be
return i<r.i || (i==r.i && j<r.j);
[toc] | [prev] | [next] | [standalone]
| From | Ralf Goertz <me@myprovider.invalid> |
|---|---|
| Date | 2020-01-05 16:06 +0100 |
| Message-ID | <qusu17$ld9$1@dont-email.me> |
| In reply to | #71118 |
Am Sat, 4 Jan 2020 21:46:28 -0000 (UTC)
schrieb Ike Naar <ike@sdf.lonestar.org>:
> On 2020-01-02, Ralf Goertz <me@myprovider.invalid> wrote:
> > struct Foo {
> > int i,j;
> > bool operator<(const struct Foo &r) const { //needed for set
> > if (i<r.i) return true;
> > return j<r.j;
>
> This looks suspect.
> Do you want (2,1) to be less than (1,2) ? if you want to define a
> lexicographical order on (i,j), the comparison should be
>
> return i<r.i || (i==r.i && j<r.j);
Yeah, I know. I did get it wrong but I only defined the operator in
order to be able to use Foo with the set. I was puzzled by the compile
errors with array. I thought that the fact that array is templated could
be the reason. So I tried the non-templated Foo and the errors were
gone. I would never have guessed that the namespace was the problem.
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2020-01-05 18:24 +0000 |
| Message-ID | <slrnr14aeq.9in.grahn+nntp@frailea.sa.invalid> |
| In reply to | #71146 |
On Sun, 2020-01-05, Ralf Goertz wrote:
> Am Sat, 4 Jan 2020 21:46:28 -0000 (UTC)
> schrieb Ike Naar <ike@sdf.lonestar.org>:
>
>> On 2020-01-02, Ralf Goertz <me@myprovider.invalid> wrote:
>> > struct Foo {
>> > int i,j;
>> > bool operator<(const struct Foo &r) const { //needed for set
>> > if (i<r.i) return true;
>> > return j<r.j;
>>
>> This looks suspect.
>> Do you want (2,1) to be less than (1,2) ? if you want to define a
>> lexicographical order on (i,j), the comparison should be
>>
>> return i<r.i || (i==r.i && j<r.j);
>
> Yeah, I know.
I don't know why, but I feel safer defining it like this:
bool operator<(const struct Foo &r) const {
if (i==r.i) return j < r.j;
return i < r.i;
}
Another option would be std::make_pair, and comparing the pairs.
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2020-01-05 10:56 -0800 |
| Message-ID | <2fa235df-fa7d-47f7-b7aa-5bc16f0e2114@googlegroups.com> |
| In reply to | #71150 |
On Sunday, 5 January 2020 20:24:38 UTC+2, Jorgen Grahn wrote:
> On Sun, 2020-01-05, Ralf Goertz wrote:
> > Am Sat, 4 Jan 2020 21:46:28 -0000 (UTC)
> > schrieb Ike Naar <ike@sdf.lonestar.org>:
> >
> >> On 2020-01-02, Ralf Goertz <me@myprovider.invalid> wrote:
> >> > struct Foo {
> >> > int i,j;
> >> > bool operator<(const struct Foo &r) const { //needed for set
> >> > if (i<r.i) return true;
> >> > return j<r.j;
> >>
> >> This looks suspect.
> >> Do you want (2,1) to be less than (1,2) ? if you want to define a
> >> lexicographical order on (i,j), the comparison should be
> >>
> >> return i<r.i || (i==r.i && j<r.j);
> >
> > Yeah, I know.
>
> I don't know why, but I feel safer defining it like this:
>
> bool operator<(const struct Foo &r) const {
> if (i==r.i) return j < r.j;
> return i < r.i;
> }
>
> Another option would be std::make_pair, and comparing the pairs.
Funny. I checked that most usual in my code is that pattern:
return (l.a != r.a) ? l.a < r.a
: (l.b != r.b) ? l.b < r.b
: (l.c != r.c) ? l.c < r.c
: (l.d != r.d) ? l.d < r.d
: l.e < r.e;
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2020-01-05 19:55 +0000 |
| Message-ID | <slrnr14fp6.9in.grahn+nntp@frailea.sa.invalid> |
| In reply to | #71152 |
On Sun, 2020-01-05, Öö Tiib wrote:
> On Sunday, 5 January 2020 20:24:38 UTC+2, Jorgen Grahn wrote:
>> On Sun, 2020-01-05, Ralf Goertz wrote:
>> > Am Sat, 4 Jan 2020 21:46:28 -0000 (UTC)
>> > schrieb Ike Naar <ike@sdf.lonestar.org>:
>> >
>> >> On 2020-01-02, Ralf Goertz <me@myprovider.invalid> wrote:
>> >> > struct Foo {
>> >> > int i,j;
>> >> > bool operator<(const struct Foo &r) const { //needed for set
>> >> > if (i<r.i) return true;
>> >> > return j<r.j;
>> >>
>> >> This looks suspect.
>> >> Do you want (2,1) to be less than (1,2) ? if you want to define a
>> >> lexicographical order on (i,j), the comparison should be
>> >>
>> >> return i<r.i || (i==r.i && j<r.j);
>> >
>> > Yeah, I know.
>>
>> I don't know why, but I feel safer defining it like this:
>>
>> bool operator<(const struct Foo &r) const {
>> if (i==r.i) return j < r.j;
>> return i < r.i;
>> }
>>
>> Another option would be std::make_pair, and comparing the pairs.
>
> Funny. I checked that most usual in my code is that pattern:
>
> return (l.a != r.a) ? l.a < r.a
> : (l.b != r.b) ? l.b < r.b
> : (l.c != r.c) ? l.c < r.c
> : (l.d != r.d) ? l.d < r.d
> : l.e < r.e;
"The first pair that's different gets to decide." Makes sense!
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web