449,042 Members | 998 Online Need help? Post your question and get tips & solutions from a community of 449,042 IT Pros & Developers. It's quick & easy.

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

 P: n/a 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 #include #include #include #include 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 vect_; public : Foo (vector x, vector 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 (oss, " ")); 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 v1 (a1, a1 + sizeof(a1)/sizeof(*a1)); const vector 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:al****@connect.to http://mathforum.org/library/view/10978.html news://news.gmane.org/gmane.comp.lang.c++.perfometer ===================================== Jul 19 '05 #1
5 Replies

 P: n/a 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 #include #include //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 and uses CarryChar struct LongInt { // //data member carrychar. Functor //data member v, vector of characters vectorv; //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 (a)); 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<

 P: n/a "Agent Mulder" wrote in message news:bn**********@news2.tilbu1.nb.home.nl... 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. if(carrychar)v.push_back(1); v.swap(a.v); return*this; }}; [snip] -- ===================================== Alex Vinokur mailto:al****@connect.to http://mathforum.org/library/view/10978.html news://news.gmane.org/gmane.comp.lang.c++.perfometer ===================================== Jul 19 '05 #3

 P: n/a "Alex Vinokur" writes: 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(). class Foo { friend ostream& operator<< (ostream& os, const Foo& ioo); private : int sum_; 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 mi***@cowan.name Jul 19 '05 #4

 P: n/a In article , "Alex Vinokur" 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? 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::iterator, vector::iterator, vector::iterator, Foo& (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/wg2...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 Jul 19 '05 #5

 P: n/a "Howard Hinnant" wrote in message news:hi***************************@syrcnyrdrs-02-ge0.nyroc.rr.com... In article , "Alex Vinokur" 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] 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:al****@connect.to http://mathforum.org/library/view/10978.html news://news.gmane.org/gmane.comp.lang.c++.perfometer ===================================== Jul 19 '05 #6

### This discussion thread is closed

Replies have been disabled for this discussion. 