 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
kwikius Guest
|
Posted: Sun Dec 10, 2006 7:16 pm Post subject: Why no simple for_each? |
|
|
Having read the in language "for (each..) proposals I am bemused as to
why there are no std for_each overloads as below. The array version is
easily inlined and IMO will have a superior performance to one with
iterators, while the container version merely wraps the current
std::foreach. The use of functors is very easy to read, probably easier
than following with an expression, and the functors can be made generic
for common tasks. I have excluded such things as result_of
compatibility in the functors to make the code slightly smaller.
regards
Andy Little
-----------
/*
simple for_each for containers and arrays
*/
// std container version of for_each
template <typename Container, typename F>
void for_each(Container & c, F const & f)
{
std::for_each(c.begin(),c.end(),f);
}
//array version of for_each
template <typename T,int N,typename F>
void for_each(T (&ar)[N],F const & f)
{
for (int i = 0; i < N;++i){
f(ar[i]);
}
}
// sample expressions... full source provided at end
typedef double value_type;
//replace with your favourite vect
using quan::two_d::vect;
vect<value_type> box[] = {
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
};
//load a std::vector from array
std::vector<vect<value_type> > pt_vector;
for_each(box,push_back(pt_vector));
double angle = pi/2;
//rotate for both versions
for_each(box,rotate(angle));
for_each(pt_vector,rotate(angle));
// just to get cleaner output format
std::cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
std::cout.precision(2);
// do output
for_each(box,output(std::cout,'\n'));
for_each(pt_vector,output(std::cout,'\n'));
//-------Full source example with example functors
//------------------------------
// replace with your favourite 2D vector class...
#include <quan/two_d/out/vect.hpp>
//---------------------------------
#include <algorithm>
#include <vector>
/*
simple for_each for containers and arrays
*/
// std container version of for_each
template <typename Container, typename F>
void for_each(Container & c, F const & f)
{
std::for_each(c.begin(),c.end(),f);
}
//array version of for_each
template <typename T,int N,typename F>
void for_each(T (&ar)[N],F const & f)
{
for (int i = 0; i < N;++i){
f(ar[i]);
}
}
// functor to rotate a vector
// number of vertices
template <typename Angle>
struct rotate_{
rotate_(Angle const & angle)
: cos_theta (cos(angle)),
sin_theta(sin(angle)){}
double cos_theta, sin_theta;
template <typename Vect>
Vect&
operator()(Vect & in)const
{
in = in * cos_theta + perp_vector(in) * sin_theta;
return in;
}
};
// function for above so for_each doesnt need
// explicit template param on struct
template <typename Angle>
inline
rotate_<Angle>
rotate(Angle const & in)
{
return rotate_<Angle>(in);
}
// do output
template <typename CharType>
struct output_{
std::basic_ostream<CharType> & os;
CharType sep;
output_(
std::basic_ostream<CharType> & os_in,
CharType sep_in) s(os_in),sep(sep_in){}
template <typename T>
std::basic_ostream<CharType> &
operator()(T const & t)const
{
return os << t << sep;
}
};
// function returns functor above
template <typename CharType>
inline
output_<CharType>
output(std::basic_ostream<CharType>& os, CharType sep)
{
return output_<CharType>(os,sep);
}
// use with foreach to load a std container
// from another constainer or an array
template <typename Container>
struct push_back_{
Container & c;
push_back_(Container & c_in):c(c_in){}
template <typename T>
void
operator()(T const & t)const
{
return c.push_back(t);
}
};
// function returns functor above
template <typename Container>
inline
push_back_<Container> push_back(Container & c)
{
return push_back_<Container>(c);
}
double const pi = 3.14159265358979323846;
int main()
{
typedef double value_type;
using quan::two_d::vect;
vect<value_type> box[] = {
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1)
};
//copy points to a std::vector
std::vector<vect<value_type> > pt_vector;
for_each(box,push_back(pt_vector));
double angle = pi/2;
//test code for both versions
for_each(box,rotate(angle));
for_each(pt_vector,rotate(angle));
//get cleaner output format
std::cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
std::cout.precision(2);
for_each(box,output(std::cout,'\n'));
for_each(pt_vector,output(std::cout,'\n'));
return 0;
}
---
[ 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 ] |
|
| Back to top |
|
 |
Mathias Gaunard Guest
|
Posted: Mon Dec 11, 2006 4:07 pm Post subject: Re: Why no simple for_each? |
|
|
kwikius wrote:
| Quote: | The array version is
easily inlined and IMO will have a superior performance to one with
iterators
|
Actually some compilers are known to generate the same assembler going
through iterators of std::vector and with a loop like yours.
| Quote: | //array version of for_each
template <typename T,int N,typename F
void for_each(T (&ar)[N],F const & f)
{
for (int i = 0; i < N;++i){
f(ar[i]);
}
}
|
It should be size_t, not int.
---
[ 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 ] |
|
| Back to top |
|
 |
kwikius Guest
|
Posted: Mon Dec 11, 2006 5:30 pm Post subject: Re: Why no simple for_each? |
|
|
Mathias Gaunard wrote:
| Quote: | kwikius wrote:
The array version is
easily inlined and IMO will have a superior performance to one with
iterators
Actually some compilers are known to generate the same assembler going
through iterators of std::vector and with a loop like yours.
|
There is one more step with std::vector, which is checking that N is
constant (as it can change during the vectors life), whereas with the
array this is a guaranteed compile time constant, therefore allowing
less capable and cheaper optimisers to generate good code.
| Quote: | //array version of for_each
template <typename T,int N,typename F
void for_each(T (&ar)[N],F const & f)
{
for (int i = 0; i < N;++i){
f(ar[i]);
}
}
It should be size_t, not int.
|
OK. (With the minor nitpick changed ) Is this signature not preferable
as an alternative to the current approach to for_each for looping
through the complete container?
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 ] |
|
| Back to top |
|
 |
Signal9 Guest
|
Posted: Mon Dec 11, 2006 5:45 pm Post subject: Re: Why no simple for_each? |
|
|
kwikius wrote:
| Quote: | Having read the in language "for (each..) proposals I am bemused as to
why there are no std for_each overloads as below. The array version is
easily inlined and IMO will have a superior performance to one with
iterators, while the container version merely wraps the current
std::foreach. The use of functors is very easy to read, probably easier
than following with an expression, and the functors can be made generic
for common tasks. I have excluded such things as result_of
compatibility in the functors to make the code slightly smaller.
regards
Andy Little
-----------
/*
simple for_each for containers and arrays
*/
// std container version of for_each
template <typename Container, typename F
void for_each(Container & c, F const & f)
{
std::for_each(c.begin(),c.end(),f);
}
//array version of for_each
template <typename T,int N,typename F
void for_each(T (&ar)[N],F const & f)
{
for (int i = 0; i < N;++i){
f(ar[i]);
}
}
// sample expressions... full source provided at end
typedef double value_type;
//replace with your favourite vect
using quan::two_d::vect;
vect<value_type> box[] = {
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
};
//load a std::vector from array
std::vector<vect<value_type> > pt_vector;
for_each(box,push_back(pt_vector));
double angle = pi/2;
//rotate for both versions
for_each(box,rotate(angle));
for_each(pt_vector,rotate(angle));
// just to get cleaner output format
std::cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
std::cout.precision(2);
// do output
for_each(box,output(std::cout,'\n'));
for_each(pt_vector,output(std::cout,'\n'));
//-------Full source example with example functors
//------------------------------
// replace with your favourite 2D vector class...
#include <quan/two_d/out/vect.hpp
//---------------------------------
#include <algorithm
#include <vector
/*
simple for_each for containers and arrays
*/
// std container version of for_each
template <typename Container, typename F
void for_each(Container & c, F const & f)
{
std::for_each(c.begin(),c.end(),f);
}
//array version of for_each
template <typename T,int N,typename F
void for_each(T (&ar)[N],F const & f)
{
for (int i = 0; i < N;++i){
f(ar[i]);
}
}
// functor to rotate a vector
// number of vertices
template <typename Angle
struct rotate_{
rotate_(Angle const & angle)
: cos_theta (cos(angle)),
sin_theta(sin(angle)){}
double cos_theta, sin_theta;
template <typename Vect
Vect&
operator()(Vect & in)const
{
in = in * cos_theta + perp_vector(in) * sin_theta;
return in;
}
};
// function for above so for_each doesnt need
// explicit template param on struct
template <typename Angle
inline
rotate_<Angle
rotate(Angle const & in)
{
return rotate_<Angle>(in);
}
// do output
template <typename CharType
struct output_{
std::basic_ostream<CharType> & os;
CharType sep;
output_(
std::basic_ostream<CharType> & os_in,
CharType sep_in) s(os_in),sep(sep_in){}
template <typename T
std::basic_ostream<CharType> &
operator()(T const & t)const
{
return os << t << sep;
}
};
// function returns functor above
template <typename CharType
inline
output_<CharType
output(std::basic_ostream<CharType>& os, CharType sep)
{
return output_<CharType>(os,sep);
}
// use with foreach to load a std container
// from another constainer or an array
template <typename Container
struct push_back_{
Container & c;
push_back_(Container & c_in):c(c_in){}
template <typename T
void
operator()(T const & t)const
{
return c.push_back(t);
}
};
// function returns functor above
template <typename Container
inline
push_back_<Container> push_back(Container & c)
{
return push_back_<Container>(c);
}
double const pi = 3.14159265358979323846;
int main()
{
typedef double value_type;
using quan::two_d::vect;
vect<value_type> box[] = {
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1)
};
//copy points to a std::vector
std::vector<vect<value_type> > pt_vector;
for_each(box,push_back(pt_vector));
double angle = pi/2;
//test code for both versions
for_each(box,rotate(angle));
for_each(pt_vector,rotate(angle));
//get cleaner output format
std::cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
std::cout.precision(2);
for_each(box,output(std::cout,'\n'));
for_each(pt_vector,output(std::cout,'\n'));
return 0;
}
---
[ 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 ]
|
good read ! I enjoyed that. I think that would make it a lot easier
and cleaner overall. Do you have any performance metrics ? I would be
interested in seeing the your implementation metrics vs other
alternative methods metrics.
---
[ 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 ] |
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
Posted: Mon Dec 11, 2006 11:42 pm Post subject: Re: Why no simple for_each? |
|
|
kwikius wrote:
| Quote: | Having read the in language "for (each..) proposals I am bemused as to
why there are no std for_each overloads as below.
|
This has been proposed as part of the Range lib for TR2.
| Quote: | The array version is
easily inlined and IMO will have a superior performance to one with
iterators,
|
Why? Do you have performance data to back that up?
-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 ] |
|
| Back to top |
|
 |
kwikius Guest
|
Posted: Tue Dec 12, 2006 5:07 am Post subject: Re: Why no simple for_each? |
|
|
Thorsten Ottosen wrote:
| Quote: | kwikius wrote:
Having read the in language "for (each..) proposals I am bemused as to
why there are no std for_each overloads as below.
This has been proposed as part of the Range lib for TR2.
|
Is the syntax as simple as for_each(c,f) ?
| Quote: | The array version is
easily inlined and IMO will have a superior performance to one with
iterators,
Why? Do you have performance data to back that up?
|
I havent spent a lot of time on it, but in the following on VC8 the
souped up array version appears to be around 10% faster (2800 ms to
3070 ms or so for the code at the end---->)
compiler VC8.0, Express. These were the compile flags flags: /Ox /Ob2
/Oi /Ot /Oy /GT /GL /FD /EHsc /MT /Za /FAs /Fa"Release\\"
/Fo"Release\\" /Fd"Release\vc80.pdb" /nologo /c /TP /errorReport:prompt
System Windows XP AMD Athlon 1.25 GHz
That isnt really the point I was making though. The point is that the
syntax is a lot more concise than the iterator syntax, and in most of
my code I use it for iterating the whole container.
regards
Andy Little
//------------------------------
// replace with your favourite vector class...
#include <quan/utility/timer.hpp>
#include <quan/two_d/out/vect.hpp>
//---------------------------------
#include <algorithm>
#include <vector>
/*
simple for_each for containers and arrays
*/
// std container version of for_each
template <typename Container, typename F>
void for_each(Container & c, F const & f)
{
std::for_each(c.begin(),c.end(),f);
}
//souped up array version...
// wrap the naked array so we can
// recursively unroll the loop
template <typename T,int N>
class array_wrapper{
T * data_ ;
public:
const static std::size_t size = N;
array_wrapper(T (&a) [N]): data_(a){}
typedef T * iterator;
typedef T const * const_iterator;
iterator begin() {return data_;}
const_iterator begin()const {return data_;}
iterator end() {return data_ + N;}
const_iterator end()const {return data_ + N;}
template<int N1>
T& at(){ return data_[N1];}
T const & at()const{ return data_[N1];}
};
// compile time loop unrolling impl
template <int N>
struct for_x_in_wrapper;
template <>
struct for_x_in_wrapper<0>{
template <typename ArrayWrapper, typename F>
void operator()(ArrayWrapper& a, F const & f)const
{
f(a.at<0>());
}
};
template <int N>
struct for_x_in_wrapper{
template<typename ArrayWrapper, typename F>
void operator()(ArrayWrapper& a, F const & f)const
{
BOOST_STATIC_ASSERT(( ArrayWrapper::size >= N ) );
for_x_in_wrapper<N-1> prev;
prev(a,f);
f(a.at<N>());
}
};
template <typename T,int N,typename F>
void for_each(array_wrapper<T,N> & ar,F const & f)
{
for_x_in_wrapper<N-1> ff;
ff(ar,f);
}
////////////////////////////////////////////////
//array version of for_each
template <typename T,unsigned int N,typename F>
void for_each(T (&ar)[N],F const & f)
{
array_wrapper<T,N> arw(ar);
for_each(arw,f);
/* for (unsigned int i = 0; i != N;++i){
f(ar[i]);
}*/
}
///////////////////////////////////////////////
// functor to rotate a vector
// number of vertices
template <typename Angle>
struct rotate_{
rotate_(Angle const & angle)
: cos_theta (cos(angle)),
sin_theta(sin(angle)){}
double cos_theta, sin_theta;
template <typename Vect>
Vect&
operator()(Vect & in)const
{
in = in * cos_theta + perp_vector(in) * sin_theta;
return in;
}
};
// function for above so for_each doesnt need
// explicit template param on struct
template <typename Angle>
inline
rotate_<Angle>
rotate(Angle const & in)
{
return rotate_<Angle>(in);
}
// use with foreach to load a std container
// from another constainer or an array
template <typename Container>
struct push_back_{
Container & c;
push_back_(Container & c_in):c(c_in){}
template <typename T>
void
operator()(T const & t)const
{
return c.push_back(t);
}
};
// function returns functor above
template <typename Container>
inline
push_back_<Container> push_back(Container & c)
{
return push_back_<Container>(c);
}
typedef double value_type;
using quan::two_d::vect;
//provide separate clean
// array for each version..
vect<value_type> arbox[] = {
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1)
};
vect<value_type> vbox[] = {
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(1,0),
vect<value_type>(1,1),
vect<value_type>(0,1),
vect<value_type>(0,0),
vect<value_type>(2,0),
vect<value_type>(2,1),
vect<value_type>(0,1)
};
int main()
{
double const pi = 3.14159265358979323846;
int const nloops = 10000000;
double const angle = pi/2;
//test code for both versions
quan::timer<> ar_timer;
for (int i = 0; i < nloops; ++i){
for_each(arbox,rotate(angle));
}
ar_timer.stop();
std::vector<vect<value_type> > pt_vector;
for_each(vbox,push_back(pt_vector));
quan::timer<> v_timer;
for (int i = 0; i < nloops; ++i){
for_each(pt_vector,rotate(angle));
}
v_timer.stop();
std::cout << "array time = " << ar_timer() <<'\n';
std::cout << "std::vector time = " <<v_timer() <<'\n';
return 0;
}
---
[ 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 ] |
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
Posted: Tue Dec 12, 2006 11:54 pm Post subject: Re: Why no simple for_each? |
|
|
kwikius wrote:
| Quote: | Thorsten Ottosen wrote:
kwikius wrote:
Having read the in language "for (each..) proposals I am bemused as to
why there are no std for_each overloads as below.
This has been proposed as part of the Range lib for TR2.
Is the syntax as simple as for_each(c,f) ?
|
well, yes, every time an algothm takes two iterators, it now takes one
Range.
| Quote: |
The array version is
easily inlined and IMO will have a superior performance to one with
iterators,
Why? Do you have performance data to back that up?
I havent spent a lot of time on it, but in the following on VC8 the
souped up array version appears to be around 10% faster (2800 ms to
3070 ms or so for the code at the end---->)
compiler VC8.0, Express. These were the compile flags flags: /Ox /Ob2
/Oi /Ot /Oy /GT /GL /FD /EHsc /MT /Za /FAs /Fa"Release\\"
/Fo"Release\\" /Fd"Release\vc80.pdb" /nologo /c /TP /errorReport:prompt
System Windows XP AMD Athlon 1.25 GHz
|
well, if you're unrolling the array version, then why not unroll the
iterator version?
| Quote: | That isnt really the point I was making though. The point is that the
syntax is a lot more concise than the iterator syntax, and in most of
my code I use it for iterating the whole container.
|
Right, exactly.
See
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n2068.html
and
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1871.html
and
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1871.html#overloaded-algorithms
Whether the committee will be willing to work on this, I don't really
know. I guess if concepts pass through core, the whole lot should be
upgraded to use concepts and be part of C++0x, and not a TR.
-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 ] |
|
| Back to top |
|
 |
kwikius Guest
|
Posted: Wed Dec 13, 2006 3:52 pm Post subject: Re: Why no simple for_each? |
|
|
Thorsten Ottosen wrote:
| Quote: | well, if you're unrolling the array version, then why not unroll the
iterator version?
|
Its nowhere near as simple with the variable size container as it is
when the size is a compile time integral constant as with the array.
<...>
OK this seems like a neat idea.
In the case that the range is that of the whole container though, is a
range not conceptually the same as the container? IOW in the case where
the range includes all the elements in the container, why not also
allow a container to be passed to the algorithms as a a valid range?
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 ] |
|
| Back to top |
|
 |
Guest
|
Posted: Wed Dec 13, 2006 5:59 pm Post subject: Re: Why no simple for_each? |
|
|
On Dec 13, 3:52 pm, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:
| Quote: |
In the case that the range is that of the whole container though, is a
range not conceptually the same as the container? IOW in the case where
the range includes all the elements in the container, why not also
allow a container to be passed to the algorithms as a a valid range?
|
You can. Any object with suitable begin and end member functions
qualifies as a range.
However, if my thinking is correct, mutating algorithms will have to
create std::ranges internally to cater for all of the following ranges
of non-const elements:
a) const ranges (e.g. const range<vector<int>::iterator>>, NB *not*
const_iterator)
b) non-const rvalue ranges
c) containers
The usual const T& and T&& pair of overloads would take care of a) and
b), but an (lvalue) container (case c)) would bind to the const T&
overload, which would give the algorithm only const access to the
elements.
The following boilerplate works for all three cases:
template <typename Range>
void mutator(const Range& r)
{
// This is called for rvalue and/or const ranges (cases a) and b))
std::range nonconst_lvalue_range(r);
mutator(nonconst_lvalue_range);
}
template <typename Range>
void mutator(Range& r)
{
// This is called directly for non-const lvalue ranges, including
containers
// This is where the algorithm's code lives
std::begin(r) // ... etc ...
}
(enable_if could be used to ensure the elements are non-const)
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 ] |
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
Posted: Thu Dec 14, 2006 4:48 pm Post subject: Re: Why no simple for_each? |
|
|
kwikius wrote:
| Quote: | Thorsten Ottosen wrote:
well, if you're unrolling the array version, then why not unroll the
iterator version?
Its nowhere near as simple with the variable size container as it is
when the size is a compile time integral constant as with the array.
|
If the passed range is an array, the begin and end iterators will be
pointers that is known at compilte-time.
-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 ] |
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
Posted: Thu Dec 14, 2006 4:57 pm Post subject: Re: Why no simple for_each? |
|
|
tasjaevan (AT) gmail (DOT) com wrote:
| Quote: |
On Dec 13, 3:52 pm, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:
In the case that the range is that of the whole container though, is a
range not conceptually the same as the container? IOW in the case where
the range includes all the elements in the container, why not also
allow a container to be passed to the algorithms as a a valid range?
You can. Any object with suitable begin and end member functions
qualifies as a range.
|
Exactly.
| Quote: | However, if my thinking is correct, mutating algorithms will have to
create std::ranges internally to cater for all of the following ranges
of non-const elements:
a) const ranges (e.g. const range<vector<int>::iterator>>, NB *not*
const_iterator)
b) non-const rvalue ranges
c) containers
The usual const T& and T&& pair of overloads would take care of a) and
b), but an (lvalue) container (case c)) would bind to the const T&
overload, which would give the algorithm only const access to the
elements.
|
I'm not sure you need to make it that complicated. For example,
template< class RandomAccessRange >
void sort( RandomAccessRange&& r );
should be enough to support a), b) and c) AFAICT.
-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 ] |
|
| Back to top |
|
 |
kwikius Guest
|
Posted: Thu Dec 14, 2006 8:26 pm Post subject: Re: Why no simple for_each? |
|
|
Thorsten Ottosen wrote:
| Quote: | tasjaevan (AT) gmail (DOT) com wrote:
On Dec 13, 3:52 pm, "kwikius" <a...@servocomm.freeserve.co.uk> wrote:
In the case that the range is that of the whole container though, is a
range not conceptually the same as the container? IOW in the case where
the range includes all the elements in the container, why not also
allow a container to be passed to the algorithms as a a valid range?
You can. Any object with suitable begin and end member functions
qualifies as a range.
Exactly.
|
OK. Thats cleared that up. So range is a Concept and a container with
begin, end iterators is a model. I didnt see that in the proposals, so
I thought there must be some reason that it didnt apply. That seems to
be the major selling point of Range in that case,one less hurdle for
beginning C++ programmers when using containers.
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 ] |
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
|
| Back to top |
|
 |
Guest
|
Posted: Fri Dec 15, 2006 3:45 pm Post subject: Re: Why no simple for_each? |
|
|
On Dec 14, 4:57 pm, Thorsten Ottosen <thorsten.otto...@dezide.com>
wrote:
| Quote: |
I'm not sure you need to make it that complicated. For example,
template< class RandomAccessRange
void sort( RandomAccessRange&& r );
should be enough to support a), b) and c) AFAICT.
|
You're right. Sorry for the confusion.
A slight subtlety is that we'll have to 'call' remove_reference on
RandomAccessRange before passing it to a trait metafunction.
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 ] |
|
| Back to top |
|
 |
Thorsten Ottosen Guest
|
Posted: Sat Dec 16, 2006 2:41 am Post subject: Re: Why no simple for_each? |
|
|
tasjaevan (AT) gmail (DOT) com wrote:
| Quote: | On Dec 14, 4:57 pm, Thorsten Ottosen <thorsten.otto...@dezide.com
wrote:
A slight subtlety is that we'll have to 'call' remove_reference on
RandomAccessRange before passing it to a trait metafunction.
|
That's not a slight subtlety; it a very good observation, since T now
can be deduced as U& for some type U.
I think we only need to change the sentence
"Let ptr be a variable of type Range*, then the nested type is
typedef decltype( begin(*ptr) ) type;"
to
"Let ptr be a variable of type typename remove_reference<Range>::type*,
then the nested type is
typedef decltype( begin(*ptr) ) type;"
I wonder how the other tr1 type-traits handle this situation.
-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 ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|