Topic: fill_n an array of enums


Author: dsp@bdal.de (=?ISO-8859-1?Q?Daniel_Kr=FCgler?=)
Date: Fri, 8 Jul 2005 10:03:31 GMT
Raw View
Gianluca Silvestri wrote:
> Wouldn't suffice from the libray implementer's part write the fill_n
> function as:
>
> template <class OutputIterator, class Size, class T>
> void fill_n(OutputIterator first, Size n, const T& value)
> {
>     for (; (int)n > 0; ++first,(int)n--)    //the standard says that class
> Size can be convertible to an integral type
>     {
>         *first = value;
>     }
> }

No. Consider systems where e.g. std::numeric_limits<long>::max() >
std::numeric_limits<int>::max(), and a long value was provided
for n with a sufficiently large value. Or simpler than that: Consider
the situation where Size is unsigned int >
std::numeric_limits<int>::max()...

Greetings from Bremen,

Daniel

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dsp@bdal.de (=?ISO-8859-1?Q?Daniel_Kr=FCgler?=)
Date: Fri, 8 Jul 2005 10:03:02 GMT
Raw View
Falk Tannh=E4user wrote:
> How about
>   std::fill_n(array, +aTotal, false);
>=20
> According to =A7 5.3.1/6, the unary + operator forces integral promotio=
n
> on an enumeration operand.
> =A7 4.5/2 states that "an rvalue of [...] an enumeration type can be
> converted to an rvalue of the first of the following types that can
> represent all the values of its underlying type: int, unsigned int,
> long, or unsigned long" through an integral promotion.

Yes, that is cute and much better solution than my one! But I would=20
document that in production code to prevent the next team member from
removing the +...

Daniel

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: clcppmod-poster@not.a.valid.address ("Gianluca Silvestri")
Date: Fri, 8 Jul 2005 15:43:10 GMT
Raw View
""Daniel Kr   gler"" <dsp@bdal.de> ha scritto nel messaggio
news:42ce1f29$0$20194$4d4ebb8e@businessnews.de.uu.net...
| Gianluca Silvestri wrote:
| > Wouldn't suffice from the libray implementer's part write the fill_n
| > function as:
| >
| > template <class OutputIterator, class Size, class T>
| > void fill_n(OutputIterator first, Size n, const T& value)
| > {
| >     for (; (int)n > 0; ++first,(int)n--)    //the standard says that
class
| > Size can be convertible to an integral type
| >     {
| >         *first = value;
| >     }
| > }
|
| No. Consider systems where e.g. std::numeric_limits<long>::max() >
| std::numeric_limits<int>::max(), and a long value was provided
| for n with a sufficiently large value. Or simpler than that: Consider
| the situation where Size is unsigned int >
| std::numeric_limits<int>::max()...
|
| Greetings from Bremen,

Its becoming challenging :-)
what about :

template <class OutputIterator, class Size, class T>
void fill_n(OutputIterator first, Size n, const T& value)
{
unsigned long nn = n;    //assuming that the integral conversion of
parameter n yields a positive value, which I think is the implicit in the
standard.
for (; nn > 0; --nn,++first)
{
    *first = value;
}
}

Ciao,
Gianluca

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: falk.tannhauser@crf.canon.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Fri, 8 Jul 2005 17:32:49 GMT
Raw View
Daniel Kr=FCgler wrote:
> Falk Tannh=E4user wrote:
>> How about
>>   std::fill_n(array, +aTotal, false);
> Yes, that is cute and much better solution than my one! But I would=20
> document that in production code to prevent the next team member from
> removing the +...

However, I agree with the OP that the real bug is in the library
implementation which doesn't conform to =A7 25.2.5/1 requiring
std::fill_n to work for any type 'Size' being convertible to an
integral type.

The implementation

   template <class OutputIterator, class Size, class T>
   void fill_n(OutputIterator first, Size n, const T& value)
   {
     for (; n > 0; ++first, n =3D static_cast<Size>(n-1))
     {
       *first =3D value;
     }
   }

should work fine for any 'Size' convertible to an integral type,
since the conversion will take place when comparing to 0 (=A7 5.9/2)
and when subtracting 1 (=A7 5.7/1) and the static_cast is OK to
revert the conversion (=A7 5.2.9/6-7). Correct me when I'm wrong...

A decent optimiser should not produce worse code for
   n =3D static_cast<Size>(n-1)
than for
   --n
provided both are allowed and "well-behaved" for a given type
'Size'.

Falk

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: swampmonster@der-ball-ist-rund.net (Paul Groke)
Date: Tue, 12 Jul 2005 17:00:19 GMT
Raw View
Falk Tannh=E4user wrote:

>   template <class OutputIterator, class Size, class T>
>   void fill_n(OutputIterator first, Size n, const T& value)
>   {
>     for (; n > 0; ++first, n =3D static_cast<Size>(n-1))
>     {
>       *first =3D value;
>     }
>   }

How about:

   template <class OutputIterator, class Size, class T>
   void _Fill_n_impl(OutputIterator first, Size n, const T& value)
   {
     for (; n > 0; ++first, --n)
     {
       *first =3D value;
     }
   }

   template <class OutputIterator, class Size, class T>
   void fill_n(OutputIterator first, Size n, const T& value)
   {
     _Fill_n_impl (first, 0+n, value);
   }

Shouldn't the "0+n" take care of any conversion/promotion to
an appropiately sized integral type?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Wed, 13 Jul 2005 10:28:22 CST
Raw View
"Gianluca Silvestri" wrote:
> ""Daniel Kr   gler"" <dsp@bdal.de> ha scritto nel messaggio
> news:42cccbad$0$20189$4d4ebb8e@businessnews.de.uu.net...
> Gianluca Silvestri wrote:

> > compiling this piece of code on my compiler (VC++7.1) I got
> > an error saying that operator unary minus cannot be applied
> > to an enum, which is correct AFAIK.

> | Provided you meant bool array[aTotal], I would expect a
> | corresponding error in case of decrement, increment, and in
> | any case of mixed arithmetic, which would finally end in an
> | conversion to the underlying enum (That does not exclude
> | your case).

> > #include <algorithm>
> >
> > enum anEnum { aE1, aE2, aE3, aTotal};
> >
> > bool array[anEnum];

> | bool array[aTotal]; // I guess...
> Of course.

> > int main()
> > {
> >     std::fill_n(array, aTotal, false);
> > }

> > On the other hand the Standard says (25.2.5/1) that " The
> > type Size shall be convertible to an integral type (4.7,
> > 12.3)." AFAIK, an enumeration type can be converted to an
> > integral type. So Who's wrong here? The compiler, the
> > library or me?

> | I would say, the compiler, the library, **and** you are all fine. The
> Wouldn't suffice from the libray implementer's part write the
> fill_n function as:

> template <class OutputIterator, class Size, class T>
> void fill_n(OutputIterator first, Size n, const T& value)
> {
>     for (; (int)n > 0; ++first,(int)n--)    //the standard says that class
> Size can be convertible to an integral type
>     {
>         *first = value;
>     }
> }

What does this change?  The postfix -- still has precedence over
the cast, so you are still trying to decrement the enum, which
is what didn't work.  And of course, adding parentheses to
change the precedence results in trying to decrement an rvalue,
which isn't legal either.

Globally, I think the bug is in the standard.  The requirement
shouldn't be that the type is convertable to an integral type.
It should be that the type can be decremented and compared to
zero.  And your code should probably then defined operator
overloads anEnum& operator--( anEnum& ) and anEnum& operator--(
anEnum&, int ).

More generally, perhaps what is needed is a concept of a Counter
-- something that supports incrementation and decrementation,
default initialization, and comparison.  Or perhaps we should
only require the incrementation, and require the implementation
to do something like:

    CounterType i = CounterType() ;
    //  ...
    for ( ... ; i != n ; ++ i )

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dsp@bdal.de (=?ISO-8859-1?Q?Daniel_Kr=FCgler?=)
Date: Wed, 13 Jul 2005 18:42:29 GMT
Raw View
Hello James Kanze,

kanze@gabi-soft.fr wrote:
> Globally, I think the bug is in the standard.  The requirement
> shouldn't be that the type is convertable to an integral type.
> It should be that the type can be decremented and compared to
> zero. =20

This is essentially the same point of view I do have, see my recent
posting "Unnecessary restriction of fill_n". By the way:=20
uninitialized_fill_n does go essentially this route.

>And your code should probably then defined operator
> overloads anEnum& operator--( anEnum& ) and anEnum& operator--(
> anEnum&, int ).

I think that this is a very reasonable advice.

> More generally, perhaps what is needed is a concept of a Counter
> -- something that supports incrementation and decrementation,
> default initialization, and comparison.  Or perhaps we should
> only require the incrementation, and require the implementation
> to do something like:
>=20
>     CounterType i =3D CounterType() ;
>     //  ...
>     for ( ... ; i !=3D n ; ++ i )

Do you mean a "Countable" concept analogously to the Iterator concept,=20
but describing the interface and behaviour of a countable type? - Very=20
cute! The newly proposed big integer type

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1744.pdf

would/should fulfill these requirements.

Greetings from Bremen,

Daniel Kr=FCgler

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jdennett@acm.org (James Dennett)
Date: Thu, 14 Jul 2005 06:16:13 GMT
Raw View
Paul Groke wrote:
> Falk Tannh=E4user wrote:
>=20
>>   template <class OutputIterator, class Size, class T>
>>   void fill_n(OutputIterator first, Size n, const T& value)
>>   {
>>     for (; n > 0; ++first, n =3D static_cast<Size>(n-1))
>>     {
>>       *first =3D value;
>>     }
>>   }
>=20
>=20
> How about:
>=20
>   template <class OutputIterator, class Size, class T>
>   void _Fill_n_impl(OutputIterator first, Size n, const T& value)
>   {
>     for (; n > 0; ++first, --n)
>     {
>       *first =3D value;
>     }
>   }
>=20
>   template <class OutputIterator, class Size, class T>
>   void fill_n(OutputIterator first, Size n, const T& value)
>   {
>     _Fill_n_impl (first, 0+n, value);
>   }
>=20
> Shouldn't the "0+n" take care of any conversion/promotion to
> an appropiately sized integral type?

In reasonable cases, certainly, but not if there's an overloaded
operator+ that makes it unnecessary to convert n in order to add
it to 0.  Such an operator+ would not be bound by requirements on
the type Size.

It seems to me that the requirements should be specified
differently; a number of ideas of how to do so have been
proposed in this thread.

-- James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: clcppmod-poster@not.a.valid.address ("Gianluca Silvestri")
Date: Wed, 6 Jul 2005 15:51:38 GMT
Raw View
Hi,


compiling this piece of code on my compiler (VC++7.1) I got an error saying
that operator unary minus cannot be applied to an enum, which is correct
AFAIK.

#include <algorithm>

enum anEnum { aE1, aE2, aE3, aTotal};

bool array[anEnum];

int main()
{
    std::fill_n(array, aTotal, false);
}

On the other hand the Standard says (25.2.5/1) that " The type Size shall be
convertible to an integral type (4.7, 12.3)." AFAIK,  an enumeration type
can be converted to an integral type. So Who's wrong here? The compiler, the
library or me?

Thanks,
Gianluca

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ben-public-nospam@decadentplace.org.uk (Ben Hutchings)
Date: Wed, 6 Jul 2005 17:18:34 GMT
Raw View
"Gianluca Silvestri" <clcppmod-poster@not.a.valid.address> wrote:
> Hi,
>
>
> compiling this piece of code on my compiler (VC++7.1) I got an error saying
> that operator unary minus cannot be applied to an enum, which is correct
> AFAIK.
>
> #include <algorithm>
>
> enum anEnum { aE1, aE2, aE3, aTotal};
>
> bool array[anEnum];

Presumably you meant "aTotal" instead of "anEnum" here.

> int main()
> {
>     std::fill_n(array, aTotal, false);
> }

The error message I see refers to unary -- (pre-decrement).

> On the other hand the Standard says (25.2.5/1) that " The type Size shall be
> convertible to an integral type (4.7, 12.3)." AFAIK,  an enumeration type
> can be converted to an integral type. So Who's wrong here? The compiler, the
> library or me?

It seems like the library is wrong, but it's not obvious to me how it
could be corrected.  The standard doesn't say how an implementation of
fill_n should decide *which* integral type to convert its n parameter
to, in order to count steps.

--
Ben Hutchings
Nothing is ever a complete failure; it can always serve as a bad example.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dsp@bdal.de (=?ISO-8859-1?Q?Daniel_Kr=FCgler?=)
Date: Thu, 7 Jul 2005 15:30:06 GMT
Raw View
Gianluca Silvestri wrote:
> Hi,
>=20
>=20
> compiling this piece of code on my compiler (VC++7.1) I got an error sa=
ying=20
> that operator unary minus cannot be applied to an enum, which is correc=
t=20
> AFAIK.

Provided you meant bool array[aTotal], I would expect a corresponding=20
error in case of decrement, increment, and in any case of mixed=20
arithmetic, which would finally end in an conversion to the underlying=20
enum (That does not exclude your case).

> #include <algorithm>
>=20
> enum anEnum { aE1, aE2, aE3, aTotal};
>=20
> bool array[anEnum];

bool array[aTotal]; // I guess...

>=20
> int main()
> {
>     std::fill_n(array, aTotal, false);
> }
>=20
> On the other hand the Standard says (25.2.5/1) that " The type Size sha=
ll be=20
> convertible to an integral type (4.7, 12.3)." AFAIK,  an enumeration ty=
pe=20
> can be converted to an integral type. So Who's wrong here? The compiler=
, the=20
> library or me?

I would say, the compiler, the library, **and** you are all fine. The=20
problem is, that its currently not possible to deduce the underlying=20
type of an enumeration, which would be necessary to fulfill the task in=20
your case. One could argue, that the description of fill_n is=20
insufficient to realize the requests on fill_n.

A simple workaround for you would be something like:

     std::fill_n(array, ptrdiff_t(aTotal), false);

because **you** know the limits of anEnum.

Yes, the good ol' enums have some deficiencies, one of the most striking=20
one is that you can't portably deduce the underlying type, although many=20
parts of Our Holy Standard concerning enums are based on this underlying=20
integral type - its a pitty! (But extensions to enums are proposed...)

Greetings from Bremen,

Daniel Kr=FCgler

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: clcppmod-poster@not.a.valid.address ("Gianluca Silvestri")
Date: Thu, 7 Jul 2005 17:13:36 GMT
Raw View
""Daniel Kr   gler"" <dsp@bdal.de> ha scritto nel messaggio
news:42cccbad$0$20189$4d4ebb8e@businessnews.de.uu.net...
Gianluca Silvestri wrote:
> Hi,
>
>
> compiling this piece of code on my compiler (VC++7.1) I got an error
> saying
> that operator unary minus cannot be applied to an enum, which is correct
> AFAIK.

| Provided you meant bool array[aTotal], I would expect a corresponding
| error in case of decrement, increment, and in any case of mixed
| arithmetic, which would finally end in an conversion to the underlying
| enum (That does not exclude your case).

> #include <algorithm>
>
> enum anEnum { aE1, aE2, aE3, aTotal};
>
> bool array[anEnum];

| bool array[aTotal]; // I guess...
Of course.

>
> int main()
> {
>     std::fill_n(array, aTotal, false);
> }
>
> On the other hand the Standard says (25.2.5/1) that " The type Size shall
> be
> convertible to an integral type (4.7, 12.3)." AFAIK,  an enumeration type
> can be converted to an integral type. So Who's wrong here? The compiler,
> the
> library or me?

| I would say, the compiler, the library, **and** you are all fine. The
Wouldn't suffice from the libray implementer's part write the fill_n
function as:

template <class OutputIterator, class Size, class T>
void fill_n(OutputIterator first, Size n, const T& value)
{
    for (; (int)n > 0; ++first,(int)n--)    //the standard says that class
Size can be convertible to an integral type
    {
        *first = value;
    }
}

Thanks,
Gianluca

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: falk.tannhauser@crf.canon.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Thu, 7 Jul 2005 17:15:30 GMT
Raw View
X-Replace-Address:yes
Daniel Kr=FCgler wrote:
> I would say, the compiler, the library, **and** you are all fine. The=20
> problem is, that its currently not possible to deduce the underlying=20
> type of an enumeration, which would be necessary to fulfill the task in=
=20
> your case. One could argue, that the description of fill_n is=20
> insufficient to realize the requests on fill_n.
>=20
> A simple workaround for you would be something like:
>=20
>     std::fill_n(array, ptrdiff_t(aTotal), false);
>=20
> because **you** know the limits of anEnum.
>=20
> Yes, the good ol' enums have some deficiencies, one of the most strikin=
g=20
> one is that you can't portably deduce the underlying type, although man=
y=20
> parts of Our Holy Standard concerning enums are based on this underlyin=
g=20
> integral type - its a pitty! (But extensions to enums are proposed...)

How about
   std::fill_n(array, +aTotal, false);

According to =A7 5.3.1/6, the unary + operator forces integral promotion
on an enumeration operand.
=A7 4.5/2 states that "an rvalue of [...] an enumeration type can be
converted to an rvalue of the first of the following types that can
represent all the values of its underlying type: int, unsigned int,
long, or unsigned long" through an integral promotion.

Falk

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]