Topic: Deprecate the use of plain pointers as standard container iterators


Author: "dhruv" <dhruvbird@gmail.com>
Date: Tue, 30 May 2006 08:48:35 CST
Raw View
imho, std::advance is supposed to be able to add to any inerator type.
However, it doesn't return anything, so it is not very useful in such
situations. yes, boost::next() is good, but something like a
combination of next & advance would be just great!!!!
std::next_Kth(x,K) returning the iterator which is K ahead of x.

Regards,
-Dhruv.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Tue, 30 May 2006 15:20:00 GMT
Raw View
"dhruv" <dhruvbird@gmail.com> writes:

> imho, std::advance is supposed to be able to add to any inerator type.
> However, it doesn't return anything, so it is not very useful in such
> situations. yes, boost::next() is good, but something like a
> combination of next & advance would be just great!!!!
> std::next_Kth(x,K) returning the iterator which is K ahead of x.

boost::next already handles that case:

  http://www.boost.org/boost/next_prior.hpp

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@cox.net (James Dennett)
Date: Tue, 30 May 2006 15:20:04 GMT
Raw View
dhruv wrote:
> imho, std::advance is supposed to be able to add to any inerator type.
> However, it doesn't return anything, so it is not very useful in such
> situations. yes, boost::next() is good, but something like a
> combination of next & advance would be just great!!!!
> std::next_Kth(x,K) returning the iterator which is K ahead of x.

If we were to standardize boost::next, I hope we would keep
it as is, which includes an overload specifying how many
positions to advance by.

-- 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.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@cox.net (James Dennett)
Date: Mon, 22 May 2006 01:28:26 GMT
Raw View
Nicola Musatti wrote:
> James Dennett wrote:
>> Nicola Musatti wrote:
> [...]
>>> If std::vector<>::iterator is a pointer the expression ++v.begin() is
>>> invalid because it attempts to modify an rvalue.
>> std::sort(boost::next(v.begin()), v.end());
>
> Imagine for a moment that you are teaching the standard library to not
> very expert C++ programmers. Would you really be happy to tell them
> that in order to advance an iterator one position they need to call a
> third party function?

I'd prefer to advise them to re-write this one in their
own library, unless they were already using boost.  If
boost was in use, I wouldn't feel bad about recommending
use of boost::next and boost::prior.

> But, wait, it will probably be in the standard in
> less than five years!

The implementation with which I have to do most of my
current work won't let me take the std::distance between
two iterators in the obvious way; I won't hold my breath
waiting for anything new to become available.  Third
party library support does move much faster than the
standardization process.  (It's Sun's CC, incidentally;
the compiler has improved a lot of late, but for backwards
compatibility reasons its default standard library has not
changed in a long, long time, and still does not assume
support for partial specialization or for template members.
Support for STLPort v4 is included, but as no third-party
libraries support that, it's not an option for us.  Sun's
reasons are valid; ABI stability of C++ on Solaris is
pretty much rock solid, but the cost is being frozen into
a (large) pre-1998 subset of C++.)

>> works and is generic (and of course boost::next is
>> trivial to implement).
>
> It's still much clumsier than ++v.begin() .

I'm not sure about that.  v.begin()+1 is more reasonable;
incrementing an rvalue seems relatively unnatural to me,
though I imagine that's influenced by C++'s specific rules.

> [...]
>>> int * find(int * b, int * e, int d) {
>>>     return b + d < e ? b + d : e;
>>> }
>
> // ...
>>>     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
>>>     std::cout << ( i != v.end() ? *i : 0 ) << '\n';
>>>
>>> If std::vector<>::iterator is a pointer the user defined find function
>>> is chosen.
>> What's to say that std::vector<T>::iterator might not be
>> a UDT defined in a namespace nested within ::std?  In that
>> case your code might also find no "find", or the wrong
>> "find"?  It sounds like you wish to require that the
>> iterators must be of a type defined in namespace ::std;
>
> No, I'm merely saying that the syntax and behaviour of the standard
> library should be consistent across platforms, which it's not.

Nor even is that of C, and nor is the underlying language.
Completely abstracting away the underlying platform is too
expensive.  The harder question is to determine how
consistent the standard library should be, and there it's
appropriate to leave behavior unspecified or implementation-
specified (or even undefined).

>> the question is whether the benefit is worth the cost,
>> which might be slower performance on some systems (as
>> well as possibly encouraging people to write code in a
>> less robust style by relying on ADL where it's not needed).
>
> Are you suggesting that pitfalls should be carefully sprinkled
> throughout the language so that people could learn more from
> experience?

I said nothing of the kind.  Using unqualified names when
you want a specific entity makes for less clear code, in
my opinion.  This pitfall affects only code which should
be better written in any case.  I will say that ADL does
have real pitfalls though, and I'm not sure that it's
inclusion was the right solution to the perceived problem,
but that's a separate issue.

I'd like to limit the number of pitfalls, but that can be
done more by making it easy to avoid the dark corners;
one way to do that is to disable ADL when you don't want
it.

As a QoI issue, a stdlib implementation ought to at least
provide a debugging mode where all iterators are UDTs,
even if the associated compiler needs raw iterators for
std::vector and std::basic_string to maximize performance.

> As to the performance related argument I'm aware of its
> existance and I consider it the most concrete one against my proposal.
> On the other hand the deprecation mechanisim is there exactly in order
> to guarantee compiler vendors enough time to fix things.

The deprecation mechanism ought to be deprecated and
replaced by one which actually results in things being
removed from the standard eventually :)

-- 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 23 May 2006 20:03:05 GMT
Raw View
kuyper@wizard.net () wrote (abridged):
> I'm not sure that constitutes a solution...

It doesn't. My mistake.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 18 May 2006 00:55:51 CST
Raw View
Dave Harris wrote:
> kuyper@wizard.net () wrote (abridged):
> > > Nicola Musatti's suggestion would be a better solution.
> >
> > But it doesn't solve the problem, it just moves it. It just means that
> > you won't have the problem with int*, but you will still have it with
> > whichever other type std::vector<int>::iterator is a typedef for.
>
> Well, to expand on his suggestion slightly, std::vector::iterator could be
> required to be a unique type. That is, for all types T and U,
>
>     typeof(std::vector<T>::iterator) == typeof(std::vector<U>::iterator)
>        if and only if typeof(T) == typeof(U).

I'm not sure that constitutes a solution to the problem Nicola is
talking about. If std::vector<T>::iterator is T*, it satisfies that
requirement.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 14 May 2006 18:28:56 GMT
Raw View
johnchx2@yahoo.com () wrote (abridged):
> > It also means we have defined an open-ended family
> > of functions rather than the exactly 2 I  wanted.
>
> What I'm trying to suggest is that defining a function with a parameter
> whose type is a typedef defined by an external module (in this case the
> standard library) is in fact very much like defining an open ended
> family of functions.

It is like defining one member of that family (albeit we don't know which
one).

I do see your point, but I don't think you see mine yet. The example below
may make it clearer.


> The header-file vs. cpp-file difference is a bit of a red herring IMHO,
> for a couple of reasons:  first, the need to put function templates in
> headers is simply a hack to get around non-conforming compilers.
> (Export *really* is in the standard; maybe someday the folks at
> Microsoft and the gcc team will get around to implementing it....)

I disagree; I don't think "export" helps much here. It's still the case
that if we change a template function's implementation, the compiler will
have to do more work than if we change a non-template function's
implementation.


> Second, even without export, you can get the same effect with an
> explicit instantiation of the template in a .cpp file.

This is better, and an under-used feature - it does solve the problem of
managing dependencies on our function's definition. However, it doesn't
solve the problem of declaring a family of functions.  For example:

    #include <vector>

    //void func( std::vector<int>::iterator );

    template <typename T> void func( T );
    template void func( std::vector<int>::iterator );

    void func( double x );

    void test() {
         func( 1 );
     }

This fails to compile because there is no definition of the template for
the int argument. If I delete the template and uncomment the simple
iterator overload, the code does compile.

(I tested this with http://www.comeaucomputing.com/tryitout/ - thank you,
Comeau.)


> But it's not just about container iterator types...it's about typedef's
> in general.

Agreed.


> You get into exactly the same issues if you try to write:
>
>   void g( size_t ) {}
>   void g( unsigned ) {}

Agreed. However, the existence of this problem does not mean we should not
fix the vector problem.

The vector problem is worse, for me, partly because I quite often need to
work with both iterators and pointers, and because if they are different
types there is no implicit conversion from one to the other. Where-as a I
can usually write single overload which will handle both size_t and
unsigned cases of g().

I also think it is easier to fix the vector problem. I think it is more
reasonable to require vector<X>::iterator to be a unique type than to
require vector<X>::size_t to be unique.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Wed, 17 May 2006 01:05:23 CST
Raw View
Dave Harris wrote:

>     #include <vector>
>
>     //void func( std::vector<int>::iterator );
>
>     template <typename T> void func( T );
>     template void func( std::vector<int>::iterator );
>
>     void func( double x );
>
>     void test() {
>          func( 1 );
>      }
>
> This fails to compile because there is no definition of the template for
> the int argument. If I delete the template and uncomment the simple
> iterator overload, the code does compile.

Yes, I think I see what you mean.  And it's true, templates do interact
awkwardly with implicit conversions.  Basically, what is needed is:

(a) one or more functions with specific, known parameter types;
overload resolution should select these for calls with actual
parameters matching or convertible to these formal parameter types;
plus...

(b) one or more functions with indeterminate parameter types, which
won't be selected by overload resolution in preference to the
"concrete" functions above, but which will match some implementation
dependent typedefs IF those typedefs aren't matched (directly or by
conversion) by one of the concrete functions.

It actually is possible to express this in C++, but it does require
some metaprogramming gymanstics (which can be mostly hidden by
boost::enable_if and boost::is_same).  Here's an example:

   #include <vector>
   #include "boost/utility/enable_if.hpp"
   #include "boost/type_traits/is_same.hpp"

   using boost::enable_if;
   using boost::is_same;

   void func( double x );
   void func( int* p );

   typedef std::vector<int>::iterator iiter_t;

   template <typename T>
   void
   func( T, typename enable_if< is_same< T, iiter_t > >::type* = 0 );

   int main()
   {
      std::vector<int> vi (5);
      func( vi.begin() );
      func( 1 );
   }

The definitions can live in a separate translation unit:

   #include <iostream>
   #include <vector>
   #include "boost/utility/enable_if.hpp"
   #include "boost/type_traits/is_same.hpp"

   using boost::enable_if;
   using boost::is_same;

   typedef std::vector<int>::iterator iiter_t;

   template <typename T>
   void func( T t, typename enable_if< is_same< T, iiter_t > >::type* )
   {
      std::cout << "Template version called: " << *t << std::endl;
   }

   template void func( std::vector<int>::iterator, void* );

   void func( double x )
   {
      std::cout << "Double version called: " << x << std::endl;
   }

   void func( int* p )
   {
      std::cout << "int* version called: " << *p << std::endl;
   }

This works and "does the right thing" regardless of whether the
vector<int>::iterator is an int* or not.

Whether this is "simpler" than demanding that vectors not use pointers
as their iterator types is, of course, another question.  But this
technique works today, without the multi-year process that would be
involved in changing the standard in a way that outlaws existing
standard library implementations.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Peter Dimov" <pdimov@gmail.com>
Date: 8 May 2006 16:50:32 GMT
Raw View
Nicola Musatti wrote:

> Hallo,
> I belive that the use of plain pointers as iterator types for standard
> library containers should be deprecated, because it limits genericity
> and portability.

It also increases performance and presents more opportunities for
optimization.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Peter Dimov" <pdimov@gmail.com>
Date: Mon, 8 May 2006 15:27:56 CST
Raw View
Nicola Musatti wrote:

> Moreover your own comment is a strong indication that I'm right:
> incrementing an iterator rvalue is OK when it is a class instance, but
> not when it is a scalar temporary? This is the kind of pitfall that
> makes C++ needlessly hard to learn and use.

Not necessarily correct, operator++ is not required to be a member.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Pete Becker <petebecker@acm.org>
Date: Mon, 8 May 2006 16:29:45 CST
Raw View
Nicola Musatti wrote:

> Pete Becker wrote:
>
>>Nicola Musatti wrote:
>>
>>
>>>The following code is valid on some platforms and not on others:
>>>
>>>    std::sort(++v.begin(), v.end());
>>
>>This form is valid on all platforms:
>>
>> std::sort(v.begin() + 1, v.end());
>
>
> But than the code is only valid for random access iterators i.e. is not
> as generic as it could be.

That's right. The original question was about doing this for a vector,
not about making it as generic as it could be. Making something as
generic as it could be is often a over-design. Making something that
solves the problem at hand is usually a better approach.

--

Pete Becker
Roundhouse Consulting, Ltd.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Mon, 8 May 2006 21:35:06 GMT
Raw View
ThosRTanner wrote:
> Thorsten Ottosen wrote:
>
>>Seungbeom Kim wrote:
>>
>>
>>>Maybe the best resolution would be to incorporate boost::next and
>>>boost::prior into the standard, but I don't see it even in TR1...
>>
>>We're working on it.
>>
>>Please see
>>
>>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>>
>
>
> Hmm. You wouldn't like to add copy_if to that list, would you?

I think there is someone doing that elsewhere. Anyhow,
the _if and _copy variants of algorihtms are actually misplaced: they
specify orthogonal behavior which should not be part of the algorithm.

I'm working on something that will replace those variants. For example,
any xxx_if variant can be replaced by

vector<int> v;
xxx( v | filtered( pred ) );

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Mon, 8 May 2006 17:37:41 CST
Raw View
Nicola Musatti wrote:
> First of all my examples may not be the best ones to show the problems
> I'm writing about, but this doesn't mean that the problems aren't
> there, so focusing too much on the details of my code is really missing
> the issue I was trying to point out.

Yes, but in order to show that there really is a problem that calls for
a change to the standard, it's helpful to provide an example where the
problem that's being demonstrated is not easily fixed by methods that
don't involve changing the standard.

> kuyper@wizard.net wrote:
> > Nicola Musatti wrote:
> [...]
> > > void f() {
> > >     std::vector<int> v;
>          //...
> > >     std::sort(++v.begin(), v.end());
> > > }
> > >
> > > If std::vector<>::iterator is a pointer the expression ++v.begin() is
> > > invalid because it attempts to modify an rvalue.
> >
> > Which opens the question: why does it try to modify an rvalue? Why not
> > use v.begin()+1 instead? As written, this code pointlessly specifies an
> > additional operation that doesn't need to be performed, which is
> > harmless when that operation can be performed, but fails when it can't
> > be. I don't think this example provides strong support for your
> > argument. It does provide support for the idea that your code should
> > never specify any actions beyond those that actually need to be taken,
> > even if those extra actions seem harmless.
>
> Change the std::vector above with std::list and your objection still
> applies yet your suggestion doesn't anymore. The code above attempts to
> modify an rvalue because it is reasonable to do so in order to write
> clearer, more generic code. Compilers have all the information
> available to produce efficient code.
>
> Moreover your own comment is a strong indication that I'm right:
> incrementing an iterator rvalue is OK when it is a class instance, but
> not when it is a scalar temporary? This is the kind of pitfall that
> makes C++ needlessly hard to learn and use.

That's an annoying long-term consequence of the C legacy. Scalar types
have different rules than class types, in ways that minimizes the
number of changes that are needed to make C code compile under C++
without change in semantics. Now that a great deal of C++ code has been
written relying on those same rules, backwards compatibility with C++
code ends up imposing the same requirement that was originally imposed
for backwards compatibility with C code. The only way to avoid such
problems completely would have been to abandon the goal of backwards
compatibility with C from the very beginning.

> I might agree to the notion that it was a mistake to allow calling non
> const member functions on rvalues, but that's too late to change now,
> isn't it?

I don't agree that it was a mistake, but I do agree that it's too late.

> > > The following code gives different results on different platforms:
> > >
> > > int * find(int * b, int * e, int d) {
> > >     return b + d < e ? b + d : e;
> > > }
>       //...
> > >     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
> > >     std::cout << ( i != v.end() ? *i : 0 ) << '\n';
> > >
> > > If std::vector<>::iterator is a pointer the user defined find function
> > > is chosen.
> >
> > "Doctor, it hurts when I hit myself in the head with a hammer."
> > "Then stop hitting yourself in the head with a hammer."
>
> This implies that I know it is a hammer. Unfortunately the C++ standard
> doesn't tell me.

The C++ standard tells you what the semantics of std::find() are, and
how overload resolution is performed on a call to find(). If overload
resolution doesn't reliably identify an overload of find() with
acceptable semantics, you should be using different syntax for the call
to ensure that an acceptable overload is identified.

> > Use std::find(), if you want to make sure that it's actually
> > std::find() that you're calling. If you actually want the compiler to
> > consider other possible overloads, make sure that any other overload
> > that could be selected has acceptable semantics, and doesn't lead to
> > ambiguity as to which overload should be selected. This is the same
> > advice that applies whenever calling any function; there's nothing
> > special about the fact that v.begin() might (or might not) be a
> > pointer.
>
> But the problem is exactly the fact that semantics are not sufficiently
> specified!

I'm confused by that statement. There are three different semantics
that I think you could be referring to:

1. The semantics of std::find(), which strike me as being fairly well
specified.

2. The semantics you want to have executed when your code calls find()
- if that's not well specified, then you've got a serious problem, that
has nothing to do with the C++ language, and everything to do with an
inaquedately specific definition of what your code should do.

3. The semantics that actually will be executed when your code calls
find(). If these are the semantics that are insufficiently specified,
it implies that you don't know enough about which overload of find()
will be called, to be sure that the semantics of that overload are
acceptable. If that's the case, you need to change the syntax of your
function call to ensure that only overloads that are actually
acceptable will be chosen. For instance, if std::find() provides the
semantics you're looking for, then call it by using std::find() rather
than find().

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Tom Widmer <tom_usenet@hotmail.com>
Date: 9 May 2006 03:10:01 GMT
Raw View
ThosRTanner wrote:
> Thorsten Ottosen wrote:
>
>>Seungbeom Kim wrote:
>>
>>
>>>Maybe the best resolution would be to incorporate boost::next and
>>>boost::prior into the standard, but I don't see it even in TR1...
>>
>>We're working on it.
>>
>>Please see
>>
>>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>>
>
>
> Hmm. You wouldn't like to add copy_if to that list, would you?

And perhaps copy_n while you're at it!

Tom

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: tom_usenet@hotmail.com (Tom Widmer)
Date: Tue, 9 May 2006 03:10:00 GMT
Raw View
Nicola Musatti wrote:

> It's still much clumsier than ++v.begin() .

To me that looks like an attempt to move the start of the container, and
not really an intuitive way to get (v.begin() + 1). Perhaps it would be
better to forbid it altogether, perhaps by having begin() return a const
rvalue.

Tom

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: andy@servocomm.freeserve.co.uk
Date: Mon, 8 May 2006 22:22:06 CST
Raw View
Thorsten Ottosen wrote:
> Alf P. Steinbach wrote:
> > * Thorsten Ottosen:
>
> >> Please see
> >>
> >> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
> >>
> >
> >
> > Titled "Crazy ideas", but they're not at all crazy.  Change the title.
>
> I think people can see beyond the title.
>
> > Also, I think it would be a good idea to add inclusion of pi and e
> > constants in <cmath> and/or <limits>.
>
> Then please write a proposal :-)

I think that std::constant<double>::pi etc  is a great idea, maybe in a
separate header for constants. I also only just found out  ( from a
post by Maxim Yegorushkin on comp.lang.c++.moderated) that this type of
constant does not need a separate definition in a source file. That
makes the use of static struct member really convenient. I hope Alf
Steinbach will go ahead and write a paper proposing that. I remember
one objection in a similar proposal on the boost developers list was
that putting the constants in a struct would prevent addition of other
constants, though I dont remember why this was a great problem, but
anyway that is what I remember.

regards
Andy Little

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: 9 May 2006 14:50:16 GMT
Raw View
kuyper@wizard.net wrote:
> Nicola Musatti wrote:
> > First of all my examples may not be the best ones to show the problems
> > I'm writing about, but this doesn't mean that the problems aren't
> > there, so focusing too much on the details of my code is really missing
> > the issue I was trying to point out.
>
> Yes, but in order to show that there really is a problem that calls for
> a change to the standard, it's helpful to provide an example where the
> problem that's being demonstrated is not easily fixed by methods that
> don't involve changing the standard.

I understand your point of view, but on the other hand what is easy for
the average reader of comp.std.c++ is not necessarily easy for the
average C++ programmer and even less so for the average C++ beginner.

In my opinion the problem(s) I showed in my original message make the
standard library unsuitable for C++ beginners. If making the language
easy to learn is really one of the goals of C++0x a serious effort
should be undertaken to remove this kind of oddity. You see my point is
not much that the ++v.begin() syntax should be valid everywhere, but
rather that it should either be valid everywhere or nowhere at all.

If we are to use vectors instead of C style arrays to teach C++ this
problem is bound to come up in the very first programs our pupils are
going to write, at a point where it's way to early to teach them about
rvalues and constness.

[...]
> > Change the std::vector above with std::list and your objection still
> > applies yet your suggestion doesn't anymore. The code above attempts to
> > modify an rvalue because it is reasonable to do so in order to write
> > clearer, more generic code. Compilers have all the information
> > available to produce efficient code.
> >
> > Moreover your own comment is a strong indication that I'm right:
> > incrementing an iterator rvalue is OK when it is a class instance, but
> > not when it is a scalar temporary? This is the kind of pitfall that
> > makes C++ needlessly hard to learn and use.
>
> That's an annoying long-term consequence of the C legacy. Scalar types
> have different rules than class types, in ways that minimizes the
> number of changes that are needed to make C code compile under C++
> without change in semantics. Now that a great deal of C++ code has been
> written relying on those same rules, backwards compatibility with C++
> code ends up imposing the same requirement that was originally imposed
> for backwards compatibility with C code. The only way to avoid such
> problems completely would have been to abandon the goal of backwards
> compatibility with C from the very beginning.

I'm aware of that and I'm not proposing to change the core language in
this respect; I'm merely suggesting that it would be a good thing to
remove the consequences of these issues from the standard library as
much as possible, especially when they happen to be platform dependent.

[...]
> The C++ standard tells you what the semantics of std::find() are, and
> how overload resolution is performed on a call to find(). If overload
> resolution doesn't reliably identify an overload of find() with
> acceptable semantics, you should be using different syntax for the call
> to ensure that an acceptable overload is identified.

Yes, but it doesn't tell me what I can expect from standard container
iterators in this respect. As it is iterators are not abstract data
types because not only the semantics, but even the syntax they support
depends on implementation details. I find this most unfortunate.

[...]
> I'm confused by that statement. There are three different semantics
> that I think you could be referring to:
[...]
> 3. The semantics that actually will be executed when your code calls
> find(). If these are the semantics that are insufficiently specified,
> it implies that you don't know enough about which overload of find()
> will be called, to be sure that the semantics of that overload are
> acceptable. If that's the case, you need to change the syntax of your
> function call to ensure that only overloads that are actually
> acceptable will be chosen. For instance, if std::find() provides the
> semantics you're looking for, then call it by using std::find() rather
> than find().

This is the problem. I claim that knowing about argument dependent
lookup, overload resolution in the presence of function template *and*
the definition of the standard library interface should be enough for
me to know exactly which overload of find() will be called in my code.
The fact that it isn't is a most unfortunate circumstance that should
be removed if at all possible.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Tue, 9 May 2006 11:09:44 CST
Raw View
Peter Dimov wrote:
> Nicola Musatti wrote:
>
> > Moreover your own comment is a strong indication that I'm right:
> > incrementing an iterator rvalue is OK when it is a class instance, but
> > not when it is a scalar temporary? This is the kind of pitfall that
> > makes C++ needlessly hard to learn and use.
>
> Not necessarily correct, operator++ is not required to be a member.

Which makes the problem even worse, doesn't it?

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Tue, 9 May 2006 11:10:38 CST
Raw View
Peter Dimov wrote:
> Nicola Musatti wrote:
>
> > Hallo,
> > I belive that the use of plain pointers as iterator types for standard
> > library containers should be deprecated, because it limits genericity
> > and portability.
>
> It also increases performance and presents more opportunities for
> optimization.

I know. A friend of mine is being hit exactly by this problem as our
common supplier moved to a standard library implementation where vector
iterators are user defined types by default.

I still wonder if the current compromise is acceptable for everyone
concerned.

Cheers,
Nicola Musatti

P.S. At least *I* would have granted him a deprecation period ;-)

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Tue, 9 May 2006 11:27:17 CST
Raw View
Nicola Musatti wrote:
> kuyper@wizard.net wrote:
.
> > 3. The semantics that actually will be executed when your code calls
> > find(). If these are the semantics that are insufficiently specified,
> > it implies that you don't know enough about which overload of find()
> > will be called, to be sure that the semantics of that overload are
> > acceptable. If that's the case, you need to change the syntax of your
> > function call to ensure that only overloads that are actually
> > acceptable will be chosen. For instance, if std::find() provides the
> > semantics you're looking for, then call it by using std::find() rather
> > than find().
>
> This is the problem. I claim that knowing about argument dependent
> lookup, overload resolution in the presence of function template *and*
> the definition of the standard library interface should be enough for
> me to know exactly which overload of find() will be called in my code.
> The fact that it isn't is a most unfortunate circumstance that should
> be removed if at all possible.

Any function with the same name as a standard library template, whose
parameter types can make it compete with that template in overload
resolution for particular values of the template parameters, can cause
exactly the same problem, even in contexts that have nothing to do with
the iterator type of standard containers. Pointers to built-in types
are generic, the name "find" is generic - you're virtually guaranteed
to have overload resolution problems when you define such a function,
and that's the problem you're really demonstrating.

The only thing that the standard guarantees about standard container
iterator types are what operations they support. If you write code
whose correct behavior depends upon anything other than the fact that
those operations are supported, and do behave as specified by the
standard, then it's bad code. Writing code that depends upon the
iterator types not being pointers is just a special case of this
general rule. If plain pointers were prohibited as standard container
iterators, it would just change which special cases cause problems, it
wouldn't avoid them.

For example, prohibiting the use of plain pointers as standard
container iterators won't prevent find(v.begin(), v.end(), 2) from
picking up an alternative definition of find(); it would require a
different alternative definition of find() than the one you gave as an
example, but whatever iterator type an implementation choses for a
given container, a find() can be written which will be selected, over
std::find(), by overload resolution. If you don't want that overload
selected, either don't provide that alternative definition of find(),
or don't leave out the std:: qualifier that forces it to be ignored.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 9 May 2006 20:24:07 GMT
Raw View
kuyper@wizard.net () wrote (abridged):
> Yes, but in order to show that there really is a problem that calls for
> a change to the standard, it's helpful to provide an example where the
> problem that's being demonstrated is not easily fixed by methods that
> don't involve changing the standard.

For me the problem is with code like:

    #include <vector>

    void func( std::vector<int>::iterator ) {}
    void func( int * ) {}

On some platforms this defines two functions, and on others it is an error
because it defines the same function twice.

The easiest attempt at a workaround is to omit the iterator overload, and
change the point of call:

     std::vector<int>::iterator i;
     int *p;
     // ... initialise i and p...

     func( p ); // Works always.
     func( &*i ); // Works if i is not v.end().
     func( &*p ); // Works if p is not NULL.
     func( i ); // Works on some platforms.

The "&*i" adds clutter, and puts a burden onto users of func() to remember
and use it, and if they forget the compiler may not warn them (depending
on the platform), and it doesn't work if i is singular. It's not very
good, really.

Nicola Musatti's suggestion would be a better solution.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: 9 May 2006 21:30:01 GMT
Raw View
Dave Harris wrote:

> For me the problem is with code like:
>
>     #include <vector>
>
>     void func( std::vector<int>::iterator ) {}
>     void func( int * ) {}
>
> On some platforms this defines two functions, and on others it is an error
> because it defines the same function twice.
>
> The easiest attempt at a workaround is to omit the iterator overload, and
> change the point of call:

I would have thought that the easiest workaround would be to replace
the iterator overload with a template:

  template < class T > void func( T ) {}

This is closer to the meaning of the original, which effectively says
"this version of func() takes a parameter of any type, if it happens to
be the same as the type of a std::vector<int>::iterator."  (The
alternate template omits the "...happens to be the same type as the
type of a std::vector<int>::iterator.." part, but you can get it back
with a concept check, if it's important.)

It seems to me that the problem is with the intuition that
std::vector<int>::iterator is a distinguished type, when in fact it's
just another name for some type about which we know little (including
whether it's a scalar or a class 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.comeaucomputing.com/csc/faq.html                      ]





Author: "4zumanga@gmail.com" <4zumanga@gmail.com>
Date: 9 May 2006 21:30:05 GMT
Raw View
Peter Dimov wrote:
>Nicola Musatti wrote:
>> Hallo,
>> I belive that the use of plain pointers as iterator types for standard
>> library containers should be deprecated, because it limits genericity
>> and portability.
>
>It also increases performance and presents more opportunities for
>optimization.

Can you provide an example of this on a modern optimising compiler, ie
where the optimiser does better with

int* i;

than it does with:

struct iterator { int* i };

About a year ago I spent quite a lot of time investigating if g++ 4 has
any problems when vector iterators are wrapped in a class, and couldn't
produce an example where the resulting assembler wasn't the same.

Of course here I'm not talking about those compilers where the vector
iterator has extra safety over what a plain pointer woudl provide. Most
compilers provide a way to switch this off.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Peter Dimov" <pdimov@gmail.com>
Date: Tue, 9 May 2006 21:35:59 CST
Raw View
4zumanga@gmail.com wrote:
> Peter Dimov wrote:
> >Nicola Musatti wrote:
> >> Hallo,
> >> I belive that the use of plain pointers as iterator types for standard
> >> library containers should be deprecated, because it limits genericity
> >> and portability.
> >
> >It also increases performance and presents more opportunities for
> >optimization.
>
> Can you provide an example of this on a modern optimising compiler, ie
> where the optimiser does better with
>
> int* i;
>
> than it does with:
>
> struct iterator { int* i };
>
> About a year ago I spent quite a lot of time investigating if g++ 4 has
> any problems when vector iterators are wrapped in a class, and couldn't
> produce an example where the resulting assembler wasn't the same.

If you consider MSVC 7.1 a modern compiler:

#include <vector>

unsigned char w1[ 1024 ];
unsigned char w2[ 1024 ];

std::vector<unsigned char> v1( 1024 );
std::vector<unsigned char> v2( 1024 );

template<class It, class It2> void copy2( It first, It last, It2 out )
{
    for( ; first != last; ++first, ++out )
    {
        *out = *first;
    }
}

int main()
{
    copy2( w1, w1 + 1024, w2 );
    copy2( v1.begin(), v1.end(), v2.begin() );
}

Here's the disassembly. The first line is replaced with the intrinsic
inline expansion of memcpy (rep movsd), the second results in a loop
that copies byte by byte. It's not even unrolled.

_main PROC NEAR     ; COMDAT

; 19   :  copy2( w1, w1 + 1024, w2 );
; 20   :  copy2( v1.begin(), v1.end(), v2.begin() );

 mov eax, DWORD PTR ?v1@@3V?$vector@EV?$allocator@E@std@@@std@@A+4
 push esi
 push edi
 mov ecx, 256    ; 00000100H
 mov esi, OFFSET FLAT:?w1@@3PAEA  ; w1
 mov edi, OFFSET FLAT:?w2@@3PAEA  ; w2
 rep movsd
 mov esi, DWORD PTR ?v1@@3V?$vector@EV?$allocator@E@std@@@std@@A+8
 cmp eax, esi
 mov ecx, DWORD PTR ?v2@@3V?$vector@EV?$allocator@E@std@@@std@@A+4
 je SHORT $L7165
$L7144:
 mov dl, BYTE PTR [eax]
 inc eax
 mov BYTE PTR [ecx], dl
 inc ecx
 cmp eax, esi
 jne SHORT $L7144
$L7165:
 pop edi

; 21   : }

 xor eax, eax
 pop esi
 ret 0
_main ENDP

This example isn't fair, though, since 1024 is clearly visible to the
compiler and the vector size is not. But even if I level out the field
a bit:

extern size_t N;

int main()
{
    copy2( w1, w1 + N, w2 );
    copy2( v1.begin(), v1.end(), v2.begin() );
}

the first line is still a memcpy:

; 21   :     copy2( w1, w1 + N, w2 );

 mov ecx, DWORD PTR ?N@@3IA   ; N
 lea ecx, DWORD PTR ?w1@@3PAEA[ecx]
 cmp ecx, OFFSET FLAT:?w1@@3PAEA  ; w1
 push esi
 je SHORT $L7054
 sub ecx, OFFSET FLAT:?w1@@3PAEA  ; w1
 mov eax, ecx
 push edi
 shr ecx, 2
 mov esi, OFFSET FLAT:?w1@@3PAEA  ; w1
 mov edi, OFFSET FLAT:?w2@@3PAEA  ; w2
 rep movsd
 mov ecx, eax
 and ecx, 3
 rep movsb
 pop edi

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Wed, 10 May 2006 10:08:17 CST
Raw View
Dave Harris wrote:
.
> For me the problem is with code like:
>
>     #include <vector>
>
>     void func( std::vector<int>::iterator ) {}
>     void func( int * ) {}
>
> On some platforms this defines two functions, and on others it is an error
> because it defines the same function twice.

I agree, this is a problem, and I don't know any good general solution
to it. It can comes up in two different ways: typedefs and template
type parameters. The best solution I know of involves adding a
construct to the language which could be used to check whether or not
two types are the same, which can be used to supress one of the two
competing definitions when they are. However, even that approach has
its problems.

> Nicola Musatti's suggestion would be a better solution.

But it doesn't solve the problem, it just moves it. It just means that
you won't have the problem with int*, but you will still have it with
whichever other type std::vector<int>::iterator is a typedef for.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: petebecker@acm.org (Pete Becker)
Date: Wed, 10 May 2006 18:21:59 GMT
Raw View
kuyper@wizard.net wrote:
>
>>Nicola Musatti's suggestion would be a better solution.
>
>
> But it doesn't solve the problem, it just moves it. It just means that
> you won't have the problem with int*, but you will still have it with
> whichever other type std::vector<int>::iterator is a typedef for.
>

It does a little more than "just" move it. It reduces the likelihood of
running into it. People write code that uses pointers far more often
than they write code that uses the internal name of a vector's iterator
type. With the Dinkumware library you'd hit it if you did this:

void func(std::vector::iterator);
void func(std::_Vector_iterator);

--

Pete Becker
Roundhouse Consulting, Ltd.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Wed, 10 May 2006 13:21:09 CST
Raw View
kuyper@wizard.net wrote:
> Nicola Musatti wrote:
[...]
> > This is the problem. I claim that knowing about argument dependent
> > lookup, overload resolution in the presence of function template *and*
> > the definition of the standard library interface should be enough for
> > me to know exactly which overload of find() will be called in my code.
> > The fact that it isn't is a most unfortunate circumstance that should
> > be removed if at all possible.
>
> Any function with the same name as a standard library template, whose
> parameter types can make it compete with that template in overload
> resolution for particular values of the template parameters, can cause
> exactly the same problem, even in contexts that have nothing to do with
> the iterator type of standard containers. Pointers to built-in types
> are generic, the name "find" is generic - you're virtually guaranteed
> to have overload resolution problems when you define such a function,
> and that's the problem you're really demonstrating.

I have no problem with that provided that, once I make sure that my
code does what I expect from it,  the simple fact that I use standard
library types doesn't make it platform dependent.

> The only thing that the standard guarantees about standard container
> iterator types are what operations they support. If you write code
> whose correct behavior depends upon anything other than the fact that
> those operations are supported, and do behave as specified by the
> standard, then it's bad code. Writing code that depends upon the
> iterator types not being pointers is just a special case of this
> general rule. If plain pointers were prohibited as standard container
> iterators, it would just change which special cases cause problems, it
> wouldn't avoid them.

The problem is that the guarantee is not inforced as well as it could
be. Use of the standard library is made dangerous needlessly. Moreover
if plain pointers were prohibited as iterators for standard containers
I would have to rely explictly on a standard library implementation
detail to get myself in the kind of trouble I exemplified. To me this
would be a very significant difference and one worth pursuing.

> For example, prohibiting the use of plain pointers as standard
> container iterators won't prevent find(v.begin(), v.end(), 2) from
> picking up an alternative definition of find(); it would require a
> different alternative definition of find() than the one you gave as an
> example, but whatever iterator type an implementation choses for a
> given container, a find() can be written which will be selected, over
> std::find(), by overload resolution. If you don't want that overload
> selected, either don't provide that alternative definition of find(),
> or don't leave out the std:: qualifier that forces it to be ignored.

True, but I challenge you to come up with an example where this effect
was also implementation dependant, without relying on features of the
language that are manifestly implementation dependant themselves.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Wed, 10 May 2006 18:36:51 GMT
Raw View
Peter Dimov wrote:
> 4zumanga@gmail.com wrote:

> If you consider MSVC 7.1 a modern compiler:
>
> #include <vector>
>
> unsigned char w1[ 1024 ];
> unsigned char w2[ 1024 ];
>
> std::vector<unsigned char> v1( 1024 );
> std::vector<unsigned char> v2( 1024 );
>
> template<class It, class It2> void copy2( It first, It last, It2 out )
> {
>     for( ; first != last; ++first, ++out )
>     {
>         *out = *first;
>     }
> }
>
> int main()
> {
>     copy2( w1, w1 + 1024, w2 );
>     copy2( v1.begin(), v1.end(), v2.begin() );
> }

FWIW, I think

v2.insert( v2.begin(), v1.begin(), v1.end() );

would result in memcpy in a good library.

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Wed, 10 May 2006 20:54:43 CST
Raw View
Nicola Musatti wrote:
> kuyper@wizard.net wrote:
,,,
> I have no problem with that provided that, once I make sure that my
> code does what I expect from it,  the simple fact that I use standard
> library types doesn't make it platform dependent.

By that argument, you should avoid using anything that depends upon,
for example, size_t. If you pass a size_t value to a function, which
overload of that function gets used may vary from one platform to
another, for exactly the same reason why your alternate version of
find() gets selected on some platforms, and not on others.

> > For example, prohibiting the use of plain pointers as standard
> > container iterators won't prevent find(v.begin(), v.end(), 2) from
> > picking up an alternative definition of find(); it would require a
> > different alternative definition of find() than the one you gave as an
> > example, but whatever iterator type an implementation choses for a
> > given container, a find() can be written which will be selected, over
> > std::find(), by overload resolution. If you don't want that overload
> > selected, either don't provide that alternative definition of find(),
> > or don't leave out the std:: qualifier that forces it to be ignored.
>
> True, but I challenge you to come up with an example where this effect
> was also implementation dependant, without relying on features of the
> language that are manifestly implementation dependant themselves.

Just replace the plain pointers from your example with smart pointers.
Smart pointers of one kind or another are already a legal option for a
standard container's iterator type, and that option could only become
more popular if plain pointers were to become prohibited. It doesn't
seem all that implausible to me that you might define a function that
uses the same smart pointer type that a standard container has chosen
for it's iterator 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.comeaucomputing.com/csc/faq.html                      ]





Author: none@none.com ("Marek Vondrak")
Date: Thu, 11 May 2006 14:41:55 GMT
Raw View
> FWIW, I think
>
> v2.insert( v2.begin(), v1.begin(), v1.end() );
>
> would result in memcpy in a good library.

But this has nothing to do with the library implementation. We are talking
about abstraction penalty of using objects instead of pointers here. The
point is that most compilers are able to transform special for-loops to
memcpy() when the induction variables are native pointers but they fail to
do so when the variables are burried inside objects.

> int main()
> {
>     copy2( w1, w1 + 1024, w2 ); // Optimized to instrinsic memcpy()
> copy2( v1.begin(), v1.end(), v2.begin() ); // Transforms to loop
> }

-- Marek


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Thu, 11 May 2006 09:42:56 CST
Raw View
Pete Becker wrote:
> kuyper@wizard.net wrote:
[...]
> > But it doesn't solve the problem, it just moves it. It just means that
> > you won't have the problem with int*, but you will still have it with
> > whichever other type std::vector<int>::iterator is a typedef for.
>
> It does a little more than "just" move it. It reduces the likelihood of
> running into it. People write code that uses pointers far more often
> than they write code that uses the internal name of a vector's iterator
> type. With the Dinkumware library you'd hit it if you did this:
>
> void func(std::vector::iterator);
> void func(std::_Vector_iterator);

My point exactly! By the way, why do you use a UDT rather than plain
pointers? I know that it is actually configurable, but I'm under the
impression that the UDT is the default choice.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: 11 May 2006 14:50:16 GMT
Raw View
kuyper@wizard.net wrote:
> Nicola Musatti wrote:
> > kuyper@wizard.net wrote:
> ,,,
> > I have no problem with that provided that, once I make sure that my
> > code does what I expect from it,  the simple fact that I use standard
> > library types doesn't make it platform dependent.
>
> By that argument, you should avoid using anything that depends upon,
> for example, size_t. If you pass a size_t value to a function, which
> overload of that function gets used may vary from one platform to
> another, for exactly the same reason why your alternate version of
> find() gets selected on some platforms, and not on others.

You are right and I consider this an indication that C++ lacks a "true
typedef" mechanism, although not necessarily as a substitute for the
current typedef. On the other hand hiding a platform specific detail is
the actual purpose of std::size_t and everybody using it should be
aware of that.

The problem that in my opinion is exemplified by my original snippet is
how a seemingly unrelated piece of code interferes with uses of the
standard library and does so in a platform related way.

[...]
> > True, but I challenge you to come up with an example where this effect
> > was also implementation dependant, without relying on features of the
> > language that are manifestly implementation dependant themselves.
>
> Just replace the plain pointers from your example with smart pointers.
> Smart pointers of one kind or another are already a legal option for a
> standard container's iterator type, and that option could only become
> more popular if plain pointers were to become prohibited. It doesn't
> seem all that implausible to me that you might define a function that
> uses the same smart pointer type that a standard container has chosen
> for it's iterator type.

You are right again. The use of any type that was not specifically
defined to be used as standard container iterator would risk causing
similar problems.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Joe" <jgreer@nsisoftware.com>
Date: Thu, 11 May 2006 09:43:22 CST
Raw View
Dave Harris wrote:
>
> For me the problem is with code like:
>
>     #include <vector>
>
>     void func( std::vector<int>::iterator ) {}
>     void func( int * ) {}
>

Isn't/wasn't there a proposal to introduce "real" typedef-s into C++.
That is in addition to having typedef, which produces a type alias,
wasn't there proposed some other construct which created a true type
from another type?  That would solve this problem quite nicely, I
think.

joe

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: 11 May 2006 15:00:05 GMT
Raw View
johnchx2@yahoo.com () wrote (abridged):
> I would have thought that the easiest workaround would be to replace
> the iterator overload with a template:

That has the several drawbacks of templates. It means the function source
now has to be in the header, when before it wasn't. It also means we have
defined an open-ended family of functions rather than the exactly 2 I
wanted. We shouldn't need templates for this.


> It seems to me that the problem is with the intuition that
> std::vector<int>::iterator is a distinguished type

In my view the intuition is fine, and the problem is that the standard
does not require implementations to match it.

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 11 May 2006 16:09:36 GMT
Raw View
kuyper@wizard.net () wrote (abridged):
> > Nicola Musatti's suggestion would be a better solution.
>
> But it doesn't solve the problem, it just moves it. It just means that
> you won't have the problem with int*, but you will still have it with
> whichever other type std::vector<int>::iterator is a typedef for.

Well, to expand on his suggestion slightly, std::vector::iterator could be
required to be a unique type. That is, for all types T and U,

    typeof(std::vector<T>::iterator) == typeof(std::vector<U>::iterator)
       if and only if typeof(T) == typeof(U).

-- Dave Harris, Nottingham, UK.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Thu, 11 May 2006 14:57:59 CST
Raw View
Dave Harris wrote:

> It also means we have defined an open-ended family
> of functions rather than the exactly 2 I  wanted.

What I'm trying to suggest is that defining a function with a parameter
whose type is a typedef defined by an external module (in this case the
standard library) is in fact very much like defining an open ended
family of functions.

When we write:

  void f ( foo_t );  // foo_t a typedef

where the definition of foo_t is left up to the user, or to some
library header (not necessarily the standard library), possibly wrapped
up in some #ifdef's (for different platforms, different build option,
etc.), we are writing a function which is expected to handle a variety
of types, just as if we had written:

  template <class T> void foo( T );

The header-file vs. cpp-file difference is a bit of a red herring IMHO,
for a couple of reasons:  first, the need to put function templates in
headers is simply a hack to get around non-conforming compilers.
(Export *really* is in the standard; maybe someday the folks at
Microsoft and the gcc team will get around to implementing it....)
Second, even without export, you can get the same effect with an
explicit instantiation of the template in a .cpp file.

> > It seems to me that the problem is with the intuition that
> > std::vector<int>::iterator is a distinguished type
>
> In my view the intuition is fine, and the problem is that the standard
> does not require implementations to match it.

But it's not just about container iterator types...it's about typedef's
in general.  You get into exactly the same issues if you try to write:

  void g( size_t ) {}
  void g( unsigned ) {}

Is that two functions, or an illegal re-definition?  The point is that
there is no type "size_t,"  just as there is no type
std::vector<int>::iterator.  These are just aliases to some other --
implementation dependent -- types.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Fri, 5 May 2006 09:38:04 CST
Raw View
Hallo,
I belive that the use of plain pointers as iterator types for standard
library containers should be deprecated, because it limits genericity
and portability.

The following code is valid on some platforms and not on others:

#include <vector>
#include <algorithm>

void f() {
    std::vector<int> v;
    v.push_back(3);
    v.push_back(2);
    v.push_back(1);
    std::sort(++v.begin(), v.end());
}

If std::vector<>::iterator is a pointer the expression ++v.begin() is
invalid because it attempts to modify an rvalue.

The following code gives different results on different platforms:

#include <vector>
#include <algorithm>
#include <iostream>

int * find(int * b, int * e, int d) {
    return b + d < e ? b + d : e;
}

int main() {
    std::vector<int> v;
    v.push_back(3);
    v.push_back(2);
    v.push_back(1);
    std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
    std::cout << ( i != v.end() ? *i : 0 ) << '\n';
}

If std::vector<>::iterator is a pointer the user defined find function
is chosen.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Fri, 5 May 2006 10:47:52 CST
Raw View
Nicola Musatti wrote:
> Hallo,
> I belive that the use of plain pointers as iterator types for standard
> library containers should be deprecated, because it limits genericity
> and portability.
>
> The following code is valid on some platforms and not on others:
>
> #include <vector>
> #include <algorithm>
>
> void f() {
>     std::vector<int> v;
>     v.push_back(3);
>     v.push_back(2);
>     v.push_back(1);
>     std::sort(++v.begin(), v.end());
> }
>
> If std::vector<>::iterator is a pointer the expression ++v.begin() is
> invalid because it attempts to modify an rvalue.

Which opens the question: why does it try to modify an rvalue? Why not
use v.begin()+1 instead? As written, this code pointlessly specifies an
additional operation that doesn't need to be performed, which is
harmless when that operation can be performed, but fails when it can't
be. I don't think this example provides strong support for your
argument. It does provide support for the idea that your code should
never specify any actions beyond those that actually need to be taken,
even if those extra actions seem harmless.

> The following code gives different results on different platforms:
>
> #include <vector>
> #include <algorithm>
> #include <iostream>
>
> int * find(int * b, int * e, int d) {
>     return b + d < e ? b + d : e;
> }
>
> int main() {
>     std::vector<int> v;
>     v.push_back(3);
>     v.push_back(2);
>     v.push_back(1);
>     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
>     std::cout << ( i != v.end() ? *i : 0 ) << '\n';
> }
>
> If std::vector<>::iterator is a pointer the user defined find function
> is chosen.

"Doctor, it hurts when I hit myself in the head with a hammer."
"Then stop hitting yourself in the head with a hammer."

Use std::find(), if you want to make sure that it's actually
std::find() that you're calling. If you actually want the compiler to
consider other possible overloads, make sure that any other overload
that could be selected has acceptable semantics, and doesn't lead to
ambiguity as to which overload should be selected. This is the same
advice that applies whenever calling any function; there's nothing
special about the fact that v.begin() might (or might not) be a
pointer.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@cox.net (James Dennett)
Date: Fri, 5 May 2006 16:12:49 GMT
Raw View
Nicola Musatti wrote:
> Hallo,
> I belive that the use of plain pointers as iterator types for standard
> library containers should be deprecated, because it limits genericity
> and portability.
>
> The following code is valid on some platforms and not on others:
>
> #include <vector>
> #include <algorithm>
>
> void f() {
>     std::vector<int> v;
>     v.push_back(3);
>     v.push_back(2);
>     v.push_back(1);
>     std::sort(++v.begin(), v.end());
> }
>
> If std::vector<>::iterator is a pointer the expression ++v.begin() is
> invalid because it attempts to modify an rvalue.

std::sort(boost::next(v.begin()), v.end());

works and is generic (and of course boost::next is
trivial to implement).

> The following code gives different results on different platforms:
>
> #include <vector>
> #include <algorithm>
> #include <iostream>
>
> int * find(int * b, int * e, int d) {
>     return b + d < e ? b + d : e;
> }
>
> int main() {
>     std::vector<int> v;
>     v.push_back(3);
>     v.push_back(2);
>     v.push_back(1);
>     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
>     std::cout << ( i != v.end() ? *i : 0 ) << '\n';
> }
>
> If std::vector<>::iterator is a pointer the user defined find function
> is chosen.

What's to say that std::vector<T>::iterator might not be
a UDT defined in a namespace nested within ::std?  In that
case your code might also find no "find", or the wrong
"find"?  It sounds like you wish to require that the
iterators must be of a type defined in namespace ::std;
the question is whether the benefit is worth the cost,
which might be slower performance on some systems (as
well as possibly encouraging people to write code in a
less robust style by relying on ADL where it's not needed).

-- 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.comeaucomputing.com/csc/faq.html                      ]





Author: Pete Becker <petebecker@acm.org>
Date: 5 May 2006 19:40:01 GMT
Raw View
Nicola Musatti wrote:

>
> The following code is valid on some platforms and not on others:
>
>     std::sort(++v.begin(), v.end());

This form is valid on all platforms:

 std::sort(v.begin() + 1, v.end());


>     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
>
> If std::vector<>::iterator is a pointer the user defined find function
> is chosen.

If you need to insist on the std version, you can say so:

 std::vector<int>::iterator i = std::find(v.begin(), v.end(), 2);

And note that the actual change would be to the container requirements,
not to vector. These minor problems are also present for user-defined
container types that return pointers as iterators.

--

Pete Becker
Roundhouse Consulting, Ltd.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: musiphil@bawi.org (Seungbeom Kim)
Date: Fri, 5 May 2006 19:39:32 GMT
Raw View
kuyper@wizard.net wrote:
> Nicola Musatti wrote:
>> Hallo,
>> I belive that the use of plain pointers as iterator types for standard
>> library containers should be deprecated, because it limits genericity
>> and portability.
>>
>> The following code is valid on some platforms and not on others:
>>
>> #include <vector>
>> #include <algorithm>
>>
>> void f() {
>>     std::vector<int> v;
>>     v.push_back(3);
>>     v.push_back(2);
>>     v.push_back(1);
>>     std::sort(++v.begin(), v.end());
>> }
>>
>> If std::vector<>::iterator is a pointer the expression ++v.begin() is
>> invalid because it attempts to modify an rvalue.
>
> Which opens the question: why does it try to modify an rvalue? Why not
> use v.begin()+1 instead?

Maybe, for consistency across different types of containers?
When v is changed into a std::list<int>, you cannot say v.begin()+1
but only ++v.begin().

Of course we have portable solutions like boost::next, but one might
think of it as rather silly to have to depend on an external library
for such a simple thing, or one might not have it in hand in the
environment he/she is working in, or one might not be allowed to use
an external library (as often in school classes). Of course it's trivial
to implement, but it's still a nuisance...

Moreover, Table 68 [Optional sequence operations] mentions --end() too:

expression
 a.back()
return type
 reference; const_reference for constant a
operational semantics
 *--a.end()
container
 vector, list, deque

so it's certainly implying that things like --a.end() should work for
containers vector, list, and deque (even though one may argue it's only
an operational "semantics").

I'm not necessarily advocating the deprecation of plain pointers as
iterators to vector, but there seem to be some good reasons why people
expect and hope ++begin() and --end() to work.

Maybe the best resolution would be to incorporate boost::next and
boost::prior into the standard, but I don't see it even in TR1...

--
Seungbeom Kim

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Sat, 6 May 2006 02:42:52 GMT
Raw View
Seungbeom Kim wrote:

> Maybe the best resolution would be to incorporate boost::next and
> boost::prior into the standard, but I don't see it even in TR1...

We're working on it.

Please see

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Alf P. Steinbach" <alfps@start.no>
Date: Sat, 6 May 2006 03:05:26 CST
Raw View
* Thorsten Ottosen:
>
> Please see
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>

Titled "Crazy ideas", but they're not at all crazy.  Change the title.

Also, I think it would be a good idea to add inclusion of pi and e
constants in <cmath> and/or <limits>.

There is existing practice for pi: having M_PI in <math.h>, but the
uppercase stems from the C heritage and may conflict with macro naming.

Here's a list of <math.h> constants from one very popular compiler:

   M_E          e          2.71828182845904523536
   M_LOG2E      log2(e)    1.44269504088896340736
   M_LOG10E     log10(e)   0.434294481903251827651
   M_LN2        ln(2)      0.693147180559945309417
   M_LN10       ln(10)     2.30258509299404568402
   M_PI         pi         3.14159265358979323846
   M_PI_2       pi/2       1.57079632679489661923
   M_PI_4       pi/4       0.785398163397448309616
   M_1_PI       1/pi       0.318309886183790671538
   M_2_PI       2/pi       0.636619772367581343076
   M_2_SQRTPI   2/sqrt(pi) 1.12837916709551257390
   M_SQRT2      sqrt(2)    1.41421356237309504880
   M_SQRT1_2    1/sqrt(2)  0.707106781186547524401

I suggest adding the logically missing constants (of the same form as
above) and using a nesting class like

   namespace std
   {
       template< typename FloatingPointType >
       struct constant
       {
           static const FloatingPointType e = ...;
           static const FloatingPointType log2e = ...;
           static const FloatingPointType log10e = ...;
           static const FloatingPointType ln2 = ...;
           static const FloatingPointType ln10 = ...;
           static const FloatingPointType pi = ...;
           static const FloatingPointType half_pi = ...;
           static const FloatingPointType quarter_pi = ...;
           static const FloatingPointType inv_pi = ...;
           static const FloatingPointType two_inv_pi = ...;
           static const FloatingPointType sqrt_pi = ...;
           static const FloatingPointType inv_sqrt_pi = ...;
           static const FloatingPointType two_inv_sqrt_pi = ...;
           static const FloatingPointType sqrt_two = ...;
           static const FloatingPointType inv_sqrt_two = ...;
       };
   }

where having it as a template allows extern linkage compile time
constants (if that matters) and the compiler's best precision per type.

Usage would be like

    typedef std::constant<double> DoubleC;

    ...
    std::cout << DoubleC::pi << std::endl;

Perhaps somebody will suggest placing the constants in
std::numeric_limits.  After all, some other "constants" live there.
However, those are "constants" relating to each type's limits, and
furthermore, people refraing from using std::numeric_limits (except in
template code) because of the verbosity and non-constantness: INT_MAX
(short constant), not std::numeric_limits<int>::max() (long call).

Motivation: (1) get the compiler's best precision, (2) avoid errors, (3)
increase readability and writeability of code, (4) ease the process of
analyzing code (a good IDE can give automatic tooltip for e.g.
std::d::pi), and, not the least, (5) it's not just silly but plain
stupid to not have pi and e constants, it's "the language with no pi".

When I've mentioned this earlier the answer has always been that
nobody's proposed it.  So, why not include it in the proposal list?

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: 6 May 2006 17:40:01 GMT
Raw View
Alf P. Steinbach wrote:
> * Thorsten Ottosen:
> >
> > Please see
> >
> > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
> >
>
> Titled "Crazy ideas", but they're not at all crazy.  Change the title.
>
> Also, I think it would be a good idea to add inclusion of pi and e
> constants in <cmath> and/or <limits>.
>
> There is existing practice for pi: having M_PI in <math.h>, but the
> uppercase stems from the C heritage and may conflict with macro naming.
>
> Here's a list of <math.h> constants from one very popular compiler:
>
>    M_E          e          2.71828182845904523536
>    M_LOG2E      log2(e)    1.44269504088896340736
>    M_LOG10E     log10(e)   0.434294481903251827651
>    M_LN2        ln(2)      0.693147180559945309417
>    M_LN10       ln(10)     2.30258509299404568402
>    M_PI         pi         3.14159265358979323846
>    M_PI_2       pi/2       1.57079632679489661923
>    M_PI_4       pi/4       0.785398163397448309616
>    M_1_PI       1/pi       0.318309886183790671538
>    M_2_PI       2/pi       0.636619772367581343076
>    M_2_SQRTPI   2/sqrt(pi) 1.12837916709551257390
>    M_SQRT2      sqrt(2)    1.41421356237309504880
>    M_SQRT1_2    1/sqrt(2)  0.707106781186547524401

The POSIX technical standard defines these 13 symbolic constants in
math.h (see X/Open CAE System Interfaces and Headers Issue 4, Version 2
pg. 780 from http://www.opengroup.org). Note that POSIX does not
require that these symbols be defined as macros - so it would certainly
be permissible to declare them as const doubles for a C++ compiler.

And while the C++ standard could also add these (or similar) constants
to math.h (or cmath), it's not likely gain much. Most C++ programs are
compiled on POSIX compliant OSes today, which means that, as a
practical matter, these symbols are already available to almost any C++
programmer who wishes to use them in a program.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Sat, 6 May 2006 17:35:48 GMT
Raw View
Alf P. Steinbach wrote:
> * Thorsten Ottosen:

>> Please see
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>>
>
>
> Titled "Crazy ideas", but they're not at all crazy.  Change the title.

I think people can see beyond the title.

> Also, I think it would be a good idea to add inclusion of pi and e
> constants in <cmath> and/or <limits>.

Then please write a proposal :-)

>
> Usage would be like
>
>    typedef std::constant<double> DoubleC;
>
>    ...
>    std::cout << DoubleC::pi << std::endl;

I don't know if the typedef is needed. However, you want to
check up on the constexpr proposal. Basically, you want to make all the
constant constexpr functions, like

template<>
struct constants<float>
{
   static constexpr float pi() { return 3.14....; }
   ...
}:

This will make vaules avaible at compile-time.

> When I've mentioned this earlier the answer has always been that
> nobody's proposed it.  So, why not include it in the proposal list?atic

Because all of those proposal eventually need a more elaborate paper.
That paper was a "feeler" acting as a basis for discussion so I could
get some directions for what would be looked kindly upon by the LWG.

If you want this to happen, I suggets you write a paper. I'll be happy
to give you feedback.

best regards

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Sat, 6 May 2006 20:28:33 GMT
Raw View
thorsten.ottosen@dezide.com (Thorsten Ottosen) writes:

> Alf P. Steinbach wrote:
>> * Thorsten Ottosen:
>
>>> Please see
>>>
>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>>>
>> Titled "Crazy ideas", but they're not at all crazy.  Change the
>> title.
>
> I think people can see beyond the title.

Probably not very well.  It sets up an expectation that the proposal
isn't to be taken very seriously.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: petebecker@acm.org (Pete Becker)
Date: Sun, 7 May 2006 03:44:26 GMT
Raw View
David Abrahams wrote:

>
> Probably not very well.  It sets up an expectation that the proposal
> isn't to be taken very seriously.
>

Those of us in the LWG took it seriously.

--

Pete Becker
Roundhouse Consulting, Ltd.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Sun, 7 May 2006 03:44:44 GMT
Raw View
David Abrahams wrote:
> thorsten.ottosen@dezide.com (Thorsten Ottosen) writes:
>
>
>>Alf P. Steinbach wrote:
>>
>>>* Thorsten Ottosen:
>>
>>>>Please see
>>>>
>>>>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>>>>
>>>
>>>Titled "Crazy ideas", but they're not at all crazy.  Change the
>>>title.
>>
>>I think people can see beyond the title.

I may add that few would see them as crazy and that most people can
recognize that the issues there are real.

>
> Probably not very well.  It sets up an expectation that the proposal
> isn't to be taken very seriously.

So you would name it "14 serious ideas for C++"? :-) <g>

I'm confident that the people can see through rhe title and the amount
of time we have used in the LWG doesn't seem to suggest anything
different. People have taken the issue just as serious as theuy would
have with any other title IMO.

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Mon, 8 May 2006 10:38:10 CST
Raw View
Pete Becker wrote:
> Nicola Musatti wrote:
>
> >
> > The following code is valid on some platforms and not on others:
> >
> >     std::sort(++v.begin(), v.end());
>
> This form is valid on all platforms:
>
>  std::sort(v.begin() + 1, v.end());

But than the code is only valid for random access iterators i.e. is not
as generic as it could be.

> >     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
> >
> > If std::vector<>::iterator is a pointer the user defined find function
> > is chosen.
>
> If you need to insist on the std version, you can say so:
>
>  std::vector<int>::iterator i = std::find(v.begin(), v.end(), 2);

My point is not how to achieve the desired behaviour, but rather that
as this concerns the standard library it should be consistent across
platforms.

> And note that the actual change would be to the container requirements,
> not to vector. These minor problems are also present for user-defined
> container types that return pointers as iterators.

You are right, but I don't see these as counterarguments to my point of
view.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: 8 May 2006 15:40:11 GMT
Raw View
James Dennett wrote:
> Nicola Musatti wrote:
[...]
> > If std::vector<>::iterator is a pointer the expression ++v.begin() is
> > invalid because it attempts to modify an rvalue.
>
> std::sort(boost::next(v.begin()), v.end());

Imagine for a moment that you are teaching the standard library to not
very expert C++ programmers. Would you really be happy to tell them
that in order to advance an iterator one position they need to call a
third party function? But, wait, it will probably be in the standard in
less than five years!

> works and is generic (and of course boost::next is
> trivial to implement).

It's still much clumsier than ++v.begin() .

[...]
> > int * find(int * b, int * e, int d) {
> >     return b + d < e ? b + d : e;
> > }

// ...
> >     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
> >     std::cout << ( i != v.end() ? *i : 0 ) << '\n';
> >
> > If std::vector<>::iterator is a pointer the user defined find function
> > is chosen.
>
> What's to say that std::vector<T>::iterator might not be
> a UDT defined in a namespace nested within ::std?  In that
> case your code might also find no "find", or the wrong
> "find"?  It sounds like you wish to require that the
> iterators must be of a type defined in namespace ::std;

No, I'm merely saying that the syntax and behaviour of the standard
library should be consistent across platforms, which it's not.

> the question is whether the benefit is worth the cost,
> which might be slower performance on some systems (as
> well as possibly encouraging people to write code in a
> less robust style by relying on ADL where it's not needed).

Are you suggesting that pitfalls should be carefully sprinkled
throughout the language so that people could learn more from
experience? As to the performance related argument I'm aware of its
existance and I consider it the most concrete one against my proposal.
On the other hand the deprecation mechanisim is there exactly in order
to guarantee compiler vendors enough time to fix things.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Mon, 8 May 2006 11:27:05 CST
Raw View
First of all my examples may not be the best ones to show the problems
I'm writing about, but this doesn't mean that the problems aren't
there, so focusing too much on the details of my code is really missing
the issue I was trying to point out.

kuyper@wizard.net wrote:
> Nicola Musatti wrote:
[...]
> > void f() {
> >     std::vector<int> v;
         //...
> >     std::sort(++v.begin(), v.end());
> > }
> >
> > If std::vector<>::iterator is a pointer the expression ++v.begin() is
> > invalid because it attempts to modify an rvalue.
>
> Which opens the question: why does it try to modify an rvalue? Why not
> use v.begin()+1 instead? As written, this code pointlessly specifies an
> additional operation that doesn't need to be performed, which is
> harmless when that operation can be performed, but fails when it can't
> be. I don't think this example provides strong support for your
> argument. It does provide support for the idea that your code should
> never specify any actions beyond those that actually need to be taken,
> even if those extra actions seem harmless.

Change the std::vector above with std::list and your objection still
applies yet your suggestion doesn't anymore. The code above attempts to
modify an rvalue because it is reasonable to do so in order to write
clearer, more generic code. Compilers have all the information
available to produce efficient code.

Moreover your own comment is a strong indication that I'm right:
incrementing an iterator rvalue is OK when it is a class instance, but
not when it is a scalar temporary? This is the kind of pitfall that
makes C++ needlessly hard to learn and use.

I might agree to the notion that it was a mistake to allow calling non
const member functions on rvalues, but that's too late to change now,
isn't it?

> > The following code gives different results on different platforms:
> >
> > int * find(int * b, int * e, int d) {
> >     return b + d < e ? b + d : e;
> > }
      //...
> >     std::vector<int>::iterator i = find(v.begin(), v.end(), 2);
> >     std::cout << ( i != v.end() ? *i : 0 ) << '\n';
> >
> > If std::vector<>::iterator is a pointer the user defined find function
> > is chosen.
>
> "Doctor, it hurts when I hit myself in the head with a hammer."
> "Then stop hitting yourself in the head with a hammer."

This implies that I know it is a hammer. Unfortunately the C++ standard
doesn't tell me.

> Use std::find(), if you want to make sure that it's actually
> std::find() that you're calling. If you actually want the compiler to
> consider other possible overloads, make sure that any other overload
> that could be selected has acceptable semantics, and doesn't lead to
> ambiguity as to which overload should be selected. This is the same
> advice that applies whenever calling any function; there's nothing
> special about the fact that v.begin() might (or might not) be a
> pointer.

But the problem is exactly the fact that semantics are not sufficiently
specified! And what is bad for any function, is pure evil for a
standard library function. This is again a needless pitfall.

Cheers,
Nicola Musatti

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: Mon, 8 May 2006 11:27:12 CST
Raw View
Thorsten Ottosen wrote:
> Seungbeom Kim wrote:
>
> > Maybe the best resolution would be to incorporate boost::next and
> > boost::prior into the standard, but I don't see it even in TR1...
>
> We're working on it.
>
> Please see
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1870.html#add-iterator-utilities-from-boost
>

Hmm. You wouldn't like to add copy_if to that list, would you?

---
[ 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.comeaucomputing.com/csc/faq.html                      ]