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


Groups > comp.lang.c++ > #83667 > unrolled thread

This code is effective for modest-sized numbers, but can you tell what it does?

Started by"Graeme C." <graec58@gmail.com>
First post2022-04-22 04:41 -0700
Last post2022-06-04 07:57 -0700
Articles 11 on this page of 31 — 14 participants

Back to article view | Back to comp.lang.c++


Contents

  This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 04:41 -0700
    Re: This code is effective for modest-sized numbers, but can you tell what it does? Christian Gollwitzer <auriocus@gmx.de> - 2022-04-22 17:19 +0200
      Re: This code is effective for modest-sized numbers, but can you tell what it does? "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-04-22 17:42 +0200
        Re: This code is effective for modest-sized numbers, but can you tell what it does? red floyd <no.spam.here@its.invalid> - 2022-04-22 09:16 -0700
    Re: This code is effective for modest-sized numbers, but can you tell what it does? Frederick Gotham <cauldwell.thomas@gmail.com> - 2022-04-22 09:22 -0700
      Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 10:24 -0700
        Re: This code is effective for modest-sized numbers, but can you tell what it does? Christian Gollwitzer <auriocus@gmx.de> - 2022-04-22 20:33 +0200
          Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 17:57 -0700
    Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-22 19:18 -0700
      Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 19:40 -0700
        Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-22 20:00 -0700
          Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-23 04:21 -0700
    Re: This code is effective for modest-sized numbers, but can you tell what it does? Juha Nieminen <nospam@thanks.invalid> - 2022-04-25 05:48 +0000
      Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-25 05:27 -0700
        Re: This code is effective for modest-sized numbers, but can you tell what it does? Öö Tiib <ootiib@hot.ee> - 2022-04-25 05:40 -0700
          Re: This code is effective for modest-sized numbers, but can you tell what it does? Vir Campestris <vir.campestris@invalid.invalid> - 2022-04-25 16:48 +0100
            Re: This code is effective for modest-sized numbers, but can you tell what it does? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-04-30 03:51 -0700
              Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-30 08:28 -0700
                Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-30 10:30 -0700
                Re: This code is effective for modest-sized numbers, but can you tell what it does? Manfred <noname@add.invalid> - 2022-04-30 19:20 +0200
                  Re: This code is effective for modest-sized numbers, but can you tell what it does? Manfred <noname@add.invalid> - 2022-04-30 23:20 +0200
                  Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-30 10:40 -0700
                Re: This code is effective for modest-sized numbers, but can you tell what it does? Manfred <noname@add.invalid> - 2022-04-30 19:12 +0200
          Re: This code is effective for modest-sized numbers, but can you tell what it does? Juha Nieminen <nospam@thanks.invalid> - 2022-04-26 05:20 +0000
            Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-29 16:12 -0700
        Re: This code is effective for modest-sized numbers, but can you tell what it does? Paavo Helde <eesnimi@osa.pri.ee> - 2022-04-25 15:44 +0300
          Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-05-10 07:18 -0700
            Re: This code is effective for modest-sized numbers, but can you tell what it does? scott@slp53.sl.home (Scott Lurndal) - 2022-05-10 14:34 +0000
              Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-05-24 05:43 -0700
            Re: This code is effective for modest-sized numbers, but can you tell what it does? Paavo Helde <eesnimi@osa.pri.ee> - 2022-05-10 20:34 +0300
              Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-06-04 07:57 -0700

Page 2 of 2 — ← Prev page 1 [2]


#83906

FromManfred <noname@add.invalid>
Date2022-04-30 23:20 +0200
Message-ID<t4k970$rb4$1@gioia.aioe.org>
In reply to#83903
On 4/30/2022 7:40 PM, Andrey Tarasevich wrote:
> On 4/30/2022 10:20 AM, Manfred wrote:
>>
>> However, what you really should do is:
>>
>>    using MyVector = std::vector<int>;
>>
>>    ...
>>
>>    for (MyVector::reverse_iterator it = v.rbegin(); v.rend() != it; ++it)
>>    {
>>      ...
>>    }
>>
> 
> Well... yes and no. Reverse iterators are intended to encapsulate the 
> "offset by 1" idiom. In indexing terms it is equivalent to
> 
>    for (std::size_t i = v.size(); i > 0; --i)
>    {
>      // Remember to work with v[i - 1] instead of v[i]
>    }
> 

I wouldn't assume this. If I had to implement a reverse iterator I might 
have to do something like that, for example because the standard gives 
guarantees about "one past the end" pointers, but not about "one before 
the beginning".

But an implementation is more free than I would be. A standard library 
implementor could use, for example, some "one before the beginning" 
guarantee given by the implementation, that would lead to a different 
pattern.

> When wrapped into iterators it is superficially elegant, yet comes at a 
> price. In more performance-conscious situations it might prove to be too 
> expensive.

Hmm. Instead, I think that using a standard library feature would be 
recommended for performance reasons too.

  In such contexts a better idea would be to learn and use the
> alternative reverse iteration idioms, which are not that complicated.
> 

[toc] | [prev] | [next] | [standalone]


#83909

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-04-30 10:40 -0700
Message-ID<t4jsaj$f0p$1@dont-email.me>
In reply to#83903
On 4/30/2022 10:20 AM, Manfred wrote:
> 
> However, what you really should do is:
> 
>    using MyVector = std::vector<int>;
> 
>    ...
> 
>    for (MyVector::reverse_iterator it = v.rbegin(); v.rend() != it; ++it)
>    {
>      ...
>    }
> 

Well... yes and no. Reverse iterators are intended to encapsulate the 
"offset by 1" idiom. In indexing terms it is equivalent to

   for (std::size_t i = v.size(); i > 0; --i)
   {
     // Remember to work with v[i - 1] instead of v[i]
   }

When wrapped into iterators it is superficially elegant, yet comes at a 
price. In more performance-conscious situations it might prove to be too 
expensive. In such contexts a better idea would be to learn and use the 
alternative reverse iteration idioms, which are not that complicated.

-- 
Best regards,
Andrey Tarasevich

[toc] | [prev] | [next] | [standalone]


#83908

FromManfred <noname@add.invalid>
Date2022-04-30 19:12 +0200
Message-ID<t4jqm3$n8j$1@gioia.aioe.org>
In reply to#83898
On 4/30/2022 5:28 PM, Andrey Tarasevich wrote:
> On 4/30/2022 3:51 AM, Malcolm McLean wrote:
>> On Monday, 25 April 2022 at 16:48:28 UTC+1, Vir Campestris wrote:
>>> On 25/04/2022 13:40, Öö Tiib wrote:
>>>> The issue as I read it was about chance that int is 32 bits, the
>>>> vf[gen-1] has 2,200,000,000 elements and so the ++ will be
>>>> applied to INT_MAX that is undefined behavior.
>>> Some of us remember when int was only 16 bits...
>>>
>>> There's actually no guarantee that int and size_t are the same size,
>>> never mind the signed problem.
>>>
>>> for (int i = 0;
>>> is however traditional. I suspect at least in part because int is
>>> easiest to type.
>>>
>> If you need to interate in reverse
>>
>> for (int i = (int) v.size()-1; i >= 0; i--)
>>
>> you can't substitute a size_t.
>> You can do
>>
>> size_t i = v.size();
>> while(i--)
>> so there's a workaround.
> 
> If one needs to iterate in reverse one uses
> 
>    for (std::size_t i = v.size(); i > 0; )
>    {
>      --i;
>      ...
>    }
> 
> or
> 
>    for (std::size_t i = v.size(); i-- > 0; )
>    {
>      ...
>    }
> 
> or even plain
> 
>    for (std::size_t i = v.size(); i != -1; --i)
>    {
>      ...
>    }
> 
> These are not "workarounds". These are idioms.
> 

Change the last one to:

   for (std::size_t i = v.size(); i != 0; --i)
   {
     ...
   }

[toc] | [prev] | [next] | [standalone]


#83763

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-04-26 05:20 +0000
Message-ID<t47vee$10e7$1@gioia.aioe.org>
In reply to#83721
Öö Tiib <ootiib@hot.ee> wrote:
> On Monday, 25 April 2022 at 15:27:42 UTC+3, Tim Rentsch wrote:
>> Juha Nieminen <nos...@thanks.invalid> writes: 
>> 
>> > Graeme C. <gra...@gmail.com> wrote: 
>> 
>> [...]
>> >> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen 
>> > 
>> > std::vector::size() returns a value of type std::size_t. You 
>> > shouldn't be using an int with it.
>> I don't want to start a holy war, but in this particular case 
>> there is no problem comparing a signed type to a size_t (which is 
>> an unsigned type). More generally, whenever a value of a signed 
>> type has a non-negative value, as is obviously true in this 
>> construct, then there is never a problem comparing a value of a 
>> signed type to a value of an unsigned type. 
>> 
>> Some people prefer using an unsigned type for indexing variables 
>> like 'i' above, and that a reasonable style choice here IMO. But 
>> there is nothing logically wrong with giving 'i' a signed type 
>> here instead.
> 
> The issue as I read it was about chance that int is 32 bits, the 
> vf[gen-1] has 2,200,000,000 elements and so the ++ will be 
> applied to INT_MAX  that is undefined behavior.

Yeah, it's not that much about the signedness, but about the size.
After all, the program accepts a 'long long' value as input, so
ostensibly the vector might have more than INT_MAX and even more
than UINT_MAX elements (might not be the case with this particular
program, I haven't checked, but in general it could be).

[toc] | [prev] | [next] | [standalone]


#83887

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-04-29 16:12 -0700
Message-ID<868rrn5vrz.fsf@linuxsc.com>
In reply to#83763
Juha Nieminen <nospam@thanks.invalid> writes:

>  <<D6 F6 [05b6]>>  Tiib <ootiib@hot.ee> wrote:
>
>> On Monday, 25 April 2022 at 15:27:42 UTC+3, Tim Rentsch wrote:
>>
>>> Juha Nieminen <nos...@thanks.invalid> writes:
>>>
>>>> Graeme C. <gra...@gmail.com> wrote:
>>>
>>> [...]
>>>
>>>>> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>>
>>>> std::vector::size() returns a value of type std::size_t.  You
>>>> shouldn't be using an int with it.
>>>
>>> I don't want to start a holy war, but in this particular case
>>> there is no problem comparing a signed type to a size_t (which is
>>> an unsigned type).  More generally, whenever a value of a signed
>>> type has a non-negative value, as is obviously true in this
>>> construct, then there is never a problem comparing a value of a
>>> signed type to a value of an unsigned type.
>>>
>>> Some people prefer using an unsigned type for indexing variables
>>> like 'i' above, and that a reasonable style choice here IMO.  But
>>> there is nothing logically wrong with giving 'i' a signed type
>>> here instead.
>>
>> The issue as I read it was about chance that int is 32 bits, the
>> vf[gen-1] has 2,200,000,000 elements and so the ++ will be
>> applied to INT_MAX  that is undefined behavior.
>
> Yeah, it's not that much about the signedness, but about the size.
> After all, the program accepts a 'long long' value as input, so
> ostensibly the vector might have more than INT_MAX and even more
> than UINT_MAX elements (might not be the case with this particular
> program, I haven't checked, but in general it could be).

Does this mean that if the loop variable 'i' had been given type
'long long' then you would have no complaints?

[toc] | [prev] | [next] | [standalone]


#83722

FromPaavo Helde <eesnimi@osa.pri.ee>
Date2022-04-25 15:44 +0300
Message-ID<t4652k$296$1@dont-email.me>
In reply to#83720
25.04.2022 15:27 Tim Rentsch kirjutas:
> Juha Nieminen <nospam@thanks.invalid> writes:
> 
>> Graeme C. <graec58@gmail.com> wrote:
> 
> [...]
> 
>>>     for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>
>> std::vector::size() returns a value of type std::size_t.  You
>> shouldn't be using an int with it.
> 
> I don't want to start a holy war, but in this particular case
> there is no problem comparing a signed type to a size_t (which is
> an unsigned type).

I don't really care if such code uses signed or unsigned types. However, 
there is a problem when comparing signed and unsigned types, namely the 
gcc compiler issues warnings for them with -Wall, and sometimes these 
warnings are actually useful.

So, in order to not lose these useful warnings in the avalanche of 
non-useful ones, one should use matching types in such simple code, it 
does not cost anything.

[toc] | [prev] | [next] | [standalone]


#84022

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-05-10 07:18 -0700
Message-ID<86mtfp4gjw.fsf@linuxsc.com>
In reply to#83722
Paavo Helde <eesnimi@osa.pri.ee> writes:

> 25.04.2022 15:27 Tim Rentsch kirjutas:
>
>> Juha Nieminen <nospam@thanks.invalid> writes:
>>
>>> Graeme C. <graec58@gmail.com> wrote:
>>
>> [...]
>>
>>>>  for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>
>>> std::vector::size() returns a value of type std::size_t.  You
>>> shouldn't be using an int with it.
>>
>> I don't want to start a holy war, but in this particular case
>> there is no problem comparing a signed type to a size_t (which is
>> an unsigned type).
>
> I don't really care if such code uses signed or unsigned types.
> However, there is a problem when comparing signed and unsigned
> types, namely the gcc compiler issues warnings for them with -Wall,
> and sometimes these warnings are actually useful.

IME these warnings from gcc give false positives too often to
be used on every single compile.  Of course it can be useful
to turn them on now and then, to make sure nothing is askew,
but trying to avoid them even in all the false positive cases
is IMO more trouble than it is worth.

> So, in order to not lose these useful warnings in the avalanche of
> non-useful ones, one should use matching types in such simple code,
> it does not cost anything.

That seems plainly false.  Any change that incurs some programming
effort and disturbs what code is written obviously costs something.
A claim could be made that the cost is worth the benefit, but
clearly the cost is greater than zero.

[toc] | [prev] | [next] | [standalone]


#84024

Fromscott@slp53.sl.home (Scott Lurndal)
Date2022-05-10 14:34 +0000
Message-ID<KJueK.11561$IQK.4031@fx02.iad>
In reply to#84022
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>Paavo Helde <eesnimi@osa.pri.ee> writes:
>
>> 25.04.2022 15:27 Tim Rentsch kirjutas:
>>
>>> Juha Nieminen <nospam@thanks.invalid> writes:
>>>
>>>> Graeme C. <graec58@gmail.com> wrote:
>>>
>>> [...]
>>>
>>>>>  for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>>
>>>> std::vector::size() returns a value of type std::size_t.  You
>>>> shouldn't be using an int with it.
>>>
>>> I don't want to start a holy war, but in this particular case
>>> there is no problem comparing a signed type to a size_t (which is
>>> an unsigned type).
>>
>> I don't really care if such code uses signed or unsigned types.
>> However, there is a problem when comparing signed and unsigned
>> types, namely the gcc compiler issues warnings for them with -Wall,
>> and sometimes these warnings are actually useful.
>
>IME these warnings from gcc give false positives too often to
>be used on every single compile.  Of course it can be useful
>to turn them on now and then, to make sure nothing is askew,
>but trying to avoid them even in all the false positive cases
>is IMO more trouble than it is worth.

I beg to differ.  We include -Wall and -Werror on all compiles
(well over 2 million lines of C/C++).

It is far too common for C programmers to use 'int' when
the domain of the value doesn't include negative numbers.

[toc] | [prev] | [next] | [standalone]


#84253

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-05-24 05:43 -0700
Message-ID<86leur14p7.fsf@linuxsc.com>
In reply to#84024
scott@slp53.sl.home (Scott Lurndal) writes:

> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>
>> Paavo Helde <eesnimi@osa.pri.ee> writes:
>>
>>> 25.04.2022 15:27 Tim Rentsch kirjutas:
>>>
>>>> Juha Nieminen <nospam@thanks.invalid> writes:
>>>>
>>>>> Graeme C. <graec58@gmail.com> wrote:
>>>>
>>>> [...]
>>>>
>>>>>>  for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>>>
>>>>> std::vector::size() returns a value of type std::size_t.  You
>>>>> shouldn't be using an int with it.
>>>>
>>>> I don't want to start a holy war, but in this particular case
>>>> there is no problem comparing a signed type to a size_t (which is
>>>> an unsigned type).
>>>
>>> I don't really care if such code uses signed or unsigned types.
>>> However, there is a problem when comparing signed and unsigned
>>> types, namely the gcc compiler issues warnings for them with -Wall,
>>> and sometimes these warnings are actually useful.
>>
>> IME these warnings from gcc give false positives too often to
>> be used on every single compile.  Of course it can be useful
>> to turn them on now and then, to make sure nothing is askew,
>> but trying to avoid them even in all the false positive cases
>> is IMO more trouble than it is worth.
>
> I beg to differ.  We include -Wall and -Werror on all compiles
> (well over 2 million lines of C/C++).

This sounds like you are offering an implicit argument that
because your group does it all the time it follows that it's
a good idea.  I don't find such an argument convincing in any
way.

> It is far too common for C programmers to use 'int' when
> the domain of the value doesn't include negative numbers.

Such cases would still be caught if the signed/unsigned warnings
were turned on only before every code review rather than on every
single compile.

[toc] | [prev] | [next] | [standalone]


#84029

FromPaavo Helde <eesnimi@osa.pri.ee>
Date2022-05-10 20:34 +0300
Message-ID<t5e7no$bfv$1@dont-email.me>
In reply to#84022
10.05.2022 17:18 Tim Rentsch kirjutas:
> Paavo Helde <eesnimi@osa.pri.ee> writes:

>> So, in order to not lose these useful warnings in the avalanche of
>> non-useful ones, one should use matching types in such simple code,
>> it does not cost anything.
> 
> That seems plainly false.  Any change that incurs some programming
> effort and disturbs what code is written obviously costs something.
> A claim could be made that the cost is worth the benefit, but
> clearly the cost is greater than zero.

One can argue that it's using of mismatching types in a comparison which 
means non-zero programming effort.

If the types used in a comparison are of different types and especially 
of different signedness, the programmer needs to know the promotion 
rules which might depend on the operand sizes, which in turn might 
depend on the platform/implementation.

The programmer needs to think through what happens when the signed 
operand becomes negative. Is it possible and what happens then?

Even more to the point, when a maintenance programmer comes around and 
sees the code, they have to think it through again, every time. Why are 
incompatible types used in comparison? Was it an oversight and is it 
possible it might cause problems?

I will see that as a significant programming effort. YMMV.

[toc] | [prev] | [next] | [standalone]


#84531

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2022-06-04 07:57 -0700
Message-ID<864k101npb.fsf@linuxsc.com>
In reply to#84029
Paavo Helde <eesnimi@osa.pri.ee> writes:

> 10.05.2022 17:18 Tim Rentsch kirjutas:
>
>> Paavo Helde <eesnimi@osa.pri.ee> writes:
>>
>>> So, in order to not lose these useful warnings in the avalanche of
>>> non-useful ones, one should use matching types in such simple code,
>>> it does not cost anything.
>>
>> That seems plainly false.  Any change that incurs some programming
>> effort and disturbs what code is written obviously costs something.
>> A claim could be made that the cost is worth the benefit, but
>> clearly the cost is greater than zero.
>
> One can argue that it's using of mismatching types in a comparison
> which means non-zero programming effort.

That contrast is different than what I was talking about, but let
me respond to your comments here.

> If the types used in a comparison are of different types and
> especially of different signedness, the programmer needs to know the
> promotion rules which might depend on the operand sizes, which in
> turn might depend on the platform/implementation.

This is an overstatement.  Comparing two signed types, or two
unsigned types, is always safe, regardless of the widths of the
types involved.  It's only when one type is signed and the other
type is unsigned, and the unsigned type is "larger" than int, that
there is even just possibly a problem;  for example, comparing a
signed type against an unsigned char, or unsigned short, or
unsigned bit-field whose width is less than the width of unsigned
int, will never give a result different than what the unconverted
values would indicate.

> The programmer needs to think through what happens when the signed
> operand becomes negative.  Is it possible and what happens then?

These questions do need to be considered but that doesn't mean
they are difficult necessarily.  If we see a code fragment like

    int a[] = { ... };

    for( Index i = 0;  i < sizeof a / sizeof a[0];  i++  ){ ... }

it's immediately obvious that the value in 'i' is non-negative, no
matter whether the type Index is signed or unsigned.  Almost no
mental effort is needed.

> Even more to the point, when a maintenance programmer comes around
> and sees the code, they have to think it through again, every time.
> Why are incompatible types used in comparison?  Was it an oversight
> and is it possible it might cause problems?

This observation doesn't change the argument.  Any factors needing
consideration for the original developer still need consideration
for maintenance work.  The same kind of response applies.

> I will see that as a significant programming effort.  YMMV.

No one is saying that there is no programming effort involved.
Whether the effort is _significant_ in each case is a different
question.  Furthermore, the comments you make are looking at only
one side of the equation.  It isn't always practicable to choose
the two types involved so that they must be the same;  for example,
one type could be dictated by the type of a third party function
interface, and the other type could be dictated by language
semantics (subtracting one pointer from another gives a signed
type, but sizeof gives an unsigned type).  Even when it is feasible
to give the two types the same signedness, doing that may entail
other tradeoffs that have their own costs.  For example, if a
parameter 'n' has an unsigned type, we know that it has a
non-negative value.  Changing the type of 'n' to be a signed type
would mean either more code in the function to accommodate a
possible negative value of 'n', or more mental effort during
development or maintenance to consider whether such code is needed,
etc (and quite possibly both).  A proposed rule that comparands
should /always/ have the same signedness tacitly assumes that this
factor always outweighs all other factors.  That assumption simply
isn't right:  sometimes it does, but sometimes it doesn't.

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.c++


csiph-web