C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Passing the Functor-parameters in for_each() and transform()

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++)
View previous topic :: View next topic  
Author Message
Alex Vinokur
Guest





PostPosted: Sun Oct 26, 2003 2:13 pm    Post subject: Passing the Functor-parameters in for_each() and transform() Reply with quote




Functor-parameters in the for_each() and transform() algorithms are passed by value.

Might it make sense to have also algorithms for_each2() and transform2()
which pass Functor-parameters by non-const reference?


Here is some program which demonstrates probable necessity
in such forms of for_each() and transform().


====== C++ code : File foo.cpp : BEGIN ======

#include <vector>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>
using namespace std;

#define MAX_VALUE(x,y) ((x) > (y) ? (x) : (y))

class Foo
{
friend ostream& operator<< (ostream& os, const Foo& ioo);

private :
int sum_;
vector
public :
Foo (vector<int> x, vector<int> y) : sum_ (0)
{
const unsigned max_size = MAX_VALUE (x.size (), y.size ());

x.resize(max_size);
y.resize(max_size);
vect_.resize(max_size);

// ------ transform ------
transform (x.begin(), x.end(), y.begin(), vect_.begin(), *this);
cout << "sum_ = " << sum_ << " (after transform)" << endl;
cout << (*this) << endl;
// It seems that it is impossible to change sum_ through transform because
// 1) Foo copy constructor is called;
// 2) transform() doesn't return Functor-object
// -----------------------

// ------ for-each -------
for_each (vect_.begin(), vect_.end(), *this);
cout << "sum_ = " << sum_ << " (after for_each-1)" << endl;
cout << (*this) << endl;
// sum_ is not changed because
// 1) Foo copy constructor is called;
// 2) Foo value returned is not used
// -----------------------

// ------ for-each -------
*this = for_each (vect_.begin(), vect_.end(), *this);
cout << "sum_ = " << sum_ << " (after for_each-2)" << endl;
cout << (*this) << endl;
// sum_ is changed because
// * Foo value returned is used to change *this
// -----------------------

// ------ for-each -------
*this = for_each (vect_.begin(), vect_.end(), *this);
cout << "sum_ = " << sum_ << " (after for_each-3)" << endl;
cout << (*this) << endl;
// sum_ is changed because
// * Foo value returned is used to change *this
// -----------------------

}

int operator() (int n1, int n2)
{
sum_ += n1;
sum_ += n2;
return (n1 + n2);
}

void operator() (int n)
{
sum_ += n;
}


};


ostream& operator<< (ostream& os, const Foo& ioo)
{
ostringstream oss;
oss << "{ vect_ = ";
copy (ioo.vect_.begin(), ioo.vect_.end(), ostream_iterator return os << oss.str() << "}" << endl;
}


int main ()
{
const int a1[] = {1, 2, 3, 4, 5};
const int a2[] = {10, 20, 30, 40, 50, 60, 70};
const vector const vector<int> v2 (a2, a2 + sizeof(a2)/sizeof(*a2));

{ Foo (v1, v2);}

return 0;
}

====== C++ code : File foo.cpp : END ========



====== Compilation & Run : BEGIN ======

$ g++ -v
[---omitted---]
gcc version 3.3.1 (cygming special)

$ g++ foo.cpp

$ a
sum_ = 0 (after transform) // sum_ not changed
{ vect_ = 11 22 33 44 55 60 70 }

sum_ = 0 (after for_each-1) // sum_ not changed
{ vect_ = 11 22 33 44 55 60 70 }

sum_ = 295 (after for_each-2) // sum_ changed
{ vect_ = 11 22 33 44 55 60 70 }

sum_ = 590 (after for_each-3) // sum_ changed
{ vect_ = 11 22 33 44 55 60 70 }

====== Compilation & Run : END ========

--
=====================================
Alex Vinokur
mailto:alexvn (AT) connect (DOT) to
http://mathforum.org/library/view/10978.html
news://news.gmane.org/gmane.comp.lang.c++.perfometer
=====================================






Back to top
Agent Mulder
Guest





PostPosted: Sun Oct 26, 2003 4:50 pm    Post subject: Re: Passing the Functor-parameters in for_each() and transfo Reply with quote



<Alex Vinokur>
Quote:
Might it make sense to have also algorithms for_each2() and transform2()
which pass Functor-parameters by non-const reference?
/


Hi Alex, I seem to have run in the same problem as you did. Here is a little
program to show my point:



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



//global data base, holds the number base
const static char base=10;



//global data carry, needed after all
static char carry=0;



//struct CarryChar, functor for use in STL algorithm transform()
//Note how ::carry is used to address the global carry. Remove
//the :: and the local CarryChar.carry is used instead. But you
//cannot get the value AFTER the transform() algorithm, just when
//you need it most
struct CarryChar
{

//data member carry, holds the carry after addition
char carry;

//constructor
CarryChar():carry(0){::carry=0;}

//operator bool, Used once to see if there is a push_back needed
operator bool(){return::carry;}

//operator(), return sum of two characters, stores carry in carry
char operator()(const char a,const char b)
{
char c=a+b+::carry;
::carry=0;
if(c>=base){c-=base;::carry=1;}
return c;
}};





//struct LongInt, holds an expanding vector<char> and uses CarryChar
struct LongInt
{

// //data member carrychar. Functor

//data member v, vector of characters
vector<char>v;

//constructor
LongInt(char a){do v.push_back(a%base);while((a/=base)!=0);}

//operator +=, adds two LongInts and swaps the vectors
LongInt&operator+=(LongInt&a)
{
v.resize(a.v.size());
CarryChar carrychar;
transform(v.begin(),v.end(),a.v.begin(),v.begin(),carrychar);
//Here is where you need the value of carrychar.carry but it
//is outside your reach. You must use the global ::carry to
//achieve the desired result.
if(carrychar)v.push_back(1);
v.swap(a.v);
return*this;
}};



//operator<< outputs a LongInt object (to the screen)
ostream&operator<<(ostream&a,const LongInt&b)
{
copy(b.v.rbegin(),b.v.rend(),ostream_iterator return a;
}





//main. Note how LongInt(0) is forced cout<< to produce 0,1,1,2,3,5,8,13...
int main()
{
LongInt a(0);
LongInt b(1);
cout< for(int c=0;c<20;c++)cout<<(a+=b)<<'n';
return 0;
}




Back to top
Alex Vinokur
Guest





PostPosted: Mon Oct 27, 2003 5:26 pm    Post subject: Re: Passing the Functor-parameters in for_each() and transfo Reply with quote




"Agent Mulder" <mbmulder_remove_this_ (AT) home (DOT) nl> wrote

Quote:
LongInt&operator+=(LongInt&a)
{
v.resize(a.v.size());
CarryChar carrychar;
transform(v.begin(),v.end(),a.v.begin(),v.begin(),carrychar);
//Here is where you need the value of carrychar.carry but it
//is outside your reach. You must use the global ::carry to
//achieve the desired result.

Exactly. This situation caused me to ask my question.

Quote:
if(carrychar)v.push_back(1);
v.swap(a.v);
return*this;
}};
[snip]


--
=====================================
Alex Vinokur
mailto:alexvn (AT) connect (DOT) to
http://mathforum.org/library/view/10978.html
news://news.gmane.org/gmane.comp.lang.c++.perfometer
=====================================





Back to top
Micah Cowan
Guest





PostPosted: Wed Oct 29, 2003 5:05 am    Post subject: Re: Passing the Functor-parameters in for_each() and transfo Reply with quote

"Alex Vinokur" <alexvn (AT) bigfoot (DOT) com> writes:

Quote:
Functor-parameters in the for_each() and transform() algorithms are passed by value.

Might it make sense to have also algorithms for_each2() and transform2()
which pass Functor-parameters by non-const reference?


Here is some program which demonstrates probable necessity
in such forms of for_each() and transform().

<snip>

Quote:
class Foo
{
friend ostream& operator<< (ostream& os, const Foo& ioo);

private :
int sum_;


Quote:
int operator() (int n1, int n2)
{
sum_ += n1;
sum_ += n2;
return (n1 + n2);
}

void operator() (int n)
{
sum_ += n;
}

Hm. Rather than suggest dangerous versions of for_each() and
transform(), why not rather declare sum_ as mutable, allowing it
to be changed even when the Foo object was declared as const?

--
Micah J. Cowan
[email]micah (AT) cowan (DOT) name[/email]

Back to top
Howard Hinnant
Guest





PostPosted: Mon Nov 03, 2003 8:00 pm    Post subject: Re: Passing the Functor-parameters in for_each() and transfo Reply with quote

In article <bngkqk$10n0uv$1 (AT) ID-79865 (DOT) news.uni-berlin.de>,
"Alex Vinokur" <alexvn (AT) bigfoot (DOT) com> wrote:

Quote:
Functor-parameters in the for_each() and transform() algorithms are passed by
value.

Might it make sense to have also algorithms for_each2() and transform2()
which pass Functor-parameters by non-const reference?

Another solution is to explictly specify the template arguments to the
algorithms. In this way you can transform the call-by-value into a
call-by-reference. For example:

transform
<
vector vector<int>::iterator,
vector<int>::iterator,
Foo&
Quote:
(x.begin(), x.end(), y.begin(), vect_.begin(), *this);

....

sum_ = 295 (after transform)
{ vect_ = 11 22 33 44 55 60 70 }

Unfortunately the above code isn't portable. Metrowerks CodeWarrior is
the only product which has publicly stated this code is guaranteed to
work (as a conforming extension to the standard).

A defect report was submitted years ago on this issue:

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92

The consensus of the lwg is to make code such as that shown above
illegal. The state of a stateful function object does not have to be
respected. Although issue 92 is not yet set in stone, just last week
the issue was moved one step closer to being official. It will become
official (DR status) this October unless someone not only makes a lot of
noise, but is also successful at convincing others that this issue is
not being settled correctly.

Years ago I argued for the state of stateful function objects to be
respected. But I was unsuccessful in convincing others to my viewpoint.
So I settled for just allowing my own customers this behavior.

If you feel that you would like to see this behavior standardized, you
will need to go to comp.std.c++ and speak long and eloquently. You
should reference issue 92 directly, and you might also reference an
excellent article written by Klaus Kreft and Angelika Langer.

http://www.cuj.com/documents/s=8000/cujcexp1812langer/

Otherwise you can build the extra level of indirection into the functor
you pass. For example you could create a FooRef class that takes a Foo
and stores a pointer to it.

-Howard

Back to top
Alex Vinokur
Guest





PostPosted: Tue Nov 04, 2003 4:25 pm    Post subject: Re: Passing the Functor-parameters in for_each() and transfo Reply with quote


"Howard Hinnant" <hinnant (AT) metrowerks (DOT) com> wrote

Quote:
In article <bngkqk$10n0uv$1 (AT) ID-79865 (DOT) news.uni-berlin.de>,
"Alex Vinokur" <alexvn (AT) bigfoot (DOT) com> wrote:

Functor-parameters in the for_each() and transform() algorithms are passed by
value.

Might it make sense to have also algorithms for_each2() and transform2()
which pass Functor-parameters by non-const reference?

[snip]

Quote:
If you feel that you would like to see this behavior standardized, you
will need to go to comp.std.c++ and speak long and eloquently.

[snip]

I have sent my original posting to comp.std.c++ .


--
=====================================
Alex Vinokur
mailto:alexvn (AT) connect (DOT) to
http://mathforum.org/library/view/10978.html
news://news.gmane.org/gmane.comp.lang.c++.perfometer
=====================================







Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.