C++ Function objects - how to use them?
-
Hi All! Here goes the question: Mr. C++ has cleary descibed how to use function objects in Parhagraph 18.4 of his Book. The Sample code works OK, and if i use them with STL, everything`s OK Here is a simple sample: void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13)); } --- But when i try to use them some other way than in combination with STL, I get that: typedef void (*TraveseFuncPtr) (int&); void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; void TraverseVector(TraveseFuncPtr in_func) { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); tmp_a.TraverseVector(Add7); // All ok. tmp_a.TraverseVector(AddNumber(13)); //C2664 } --- And thats it. error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called I tried to dig up STL source but hell the same for_each takes a CLASS (!) as a template parameter. No functions there. Who can say anything to this? Sincerely yours, Ilya Kalujny.
-
Hi All! Here goes the question: Mr. C++ has cleary descibed how to use function objects in Parhagraph 18.4 of his Book. The Sample code works OK, and if i use them with STL, everything`s OK Here is a simple sample: void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13)); } --- But when i try to use them some other way than in combination with STL, I get that: typedef void (*TraveseFuncPtr) (int&); void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; void TraverseVector(TraveseFuncPtr in_func) { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); tmp_a.TraverseVector(Add7); // All ok. tmp_a.TraverseVector(AddNumber(13)); //C2664 } --- And thats it. error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called I tried to dig up STL source but hell the same for_each takes a CLASS (!) as a template parameter. No functions there. Who can say anything to this? Sincerely yours, Ilya Kalujny.
Yes, but what you have defined as the argument to the TraverseVector is simplay a function pointer: typedef void (*TraveseFuncPtr) (int&); Function pionters are not quite the same thing as function objects. If you want to define a function that accepts as a parameter a functor (some class which has an overloaded operator()), then you could make the function a template function and have the exact type of the class you wold pass in a template parameter. Maybe something like this: template void TraverseVector(_FunctorType in_func) { for (int i = 0; i < m_vData.size(); i++) { in_func(m_vData[i]); } } This should allow you to pass in an aribtrary type as an argument, so long as it had an overloaded operator() with the correct signature.
-
Hi All! Here goes the question: Mr. C++ has cleary descibed how to use function objects in Parhagraph 18.4 of his Book. The Sample code works OK, and if i use them with STL, everything`s OK Here is a simple sample: void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13)); } --- But when i try to use them some other way than in combination with STL, I get that: typedef void (*TraveseFuncPtr) (int&); void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; void TraverseVector(TraveseFuncPtr in_func) { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); tmp_a.TraverseVector(Add7); // All ok. tmp_a.TraverseVector(AddNumber(13)); //C2664 } --- And thats it. error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called I tried to dig up STL source but hell the same for_each takes a CLASS (!) as a template parameter. No functions there. Who can say anything to this? Sincerely yours, Ilya Kalujny.
One question: Isn't a function object (also named Functor) an object which behaves like a function?. That means this object has an overloaded operator() returning whatever the object does. This could be the explanation why the STL wants a CLASS - it calls its operator(). For your Add7-Object it would look about like
class Add7()
{
int operator()(int& out_Int)const
{
return out_Int + 7;
};
}This can be further complicated by making the class Add7 a template.
My opinions may have changed, but not the fact that I am right.
-
Hi All! Here goes the question: Mr. C++ has cleary descibed how to use function objects in Parhagraph 18.4 of his Book. The Sample code works OK, and if i use them with STL, everything`s OK Here is a simple sample: void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13)); } --- But when i try to use them some other way than in combination with STL, I get that: typedef void (*TraveseFuncPtr) (int&); void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; void TraverseVector(TraveseFuncPtr in_func) { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); tmp_a.TraverseVector(Add7); // All ok. tmp_a.TraverseVector(AddNumber(13)); //C2664 } --- And thats it. error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called I tried to dig up STL source but hell the same for_each takes a CLASS (!) as a template parameter. No functions there. Who can say anything to this? Sincerely yours, Ilya Kalujny.
One way to do what you want would be to make the traverse vector method a template method. I recommend against doing this, using STL means using all (or as much as you can manage) of it - so you should attempt to reuse tools like for_each wherever you can. for_each works along the same lines as the attached code, but may be optomised by the library for some template specialisations. The problem, passing extra information to a functor (function object), that you're putting forward is quite common, binders are a good place to look if you're interested in more generic solutions to this problem.
class A { public: std::vector < int > m_vData; template void TraverseVector(F in_func) { for (int i = 0; i < m_vData.size(); i++) { in_func(m_vData[i]); cout << m_vData[i] << endl; } } };
-
Hi All! Here goes the question: Mr. C++ has cleary descibed how to use function objects in Parhagraph 18.4 of his Book. The Sample code works OK, and if i use them with STL, everything`s OK Here is a simple sample: void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13)); } --- But when i try to use them some other way than in combination with STL, I get that: typedef void (*TraveseFuncPtr) (int&); void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; void TraverseVector(TraveseFuncPtr in_func) { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); tmp_a.TraverseVector(Add7); // All ok. tmp_a.TraverseVector(AddNumber(13)); //C2664 } --- And thats it. error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called I tried to dig up STL source but hell the same for_each takes a CLASS (!) as a template parameter. No functions there. Who can say anything to this? Sincerely yours, Ilya Kalujny.
You are not passing a pointer to a function: tmp_a.TraverseVector(AddNumber(13)); (passing the return value of AddNumber(13) to TraverseVector(), which is void/nothing/nada). This is passing a pointer to a function: tmp_a.TraverseVector(AddNumber); Trust in the code Luke. Yea right!
-
Hi All! Here goes the question: Mr. C++ has cleary descibed how to use function objects in Parhagraph 18.4 of his Book. The Sample code works OK, and if i use them with STL, everything`s OK Here is a simple sample: void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7); std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13)); } --- But when i try to use them some other way than in combination with STL, I get that: typedef void (*TraveseFuncPtr) (int&); void Add7(int& out_Int) { out_Int += 7; } class AddNumber { public: int m_iToAdd; AddNumber(int in_iToAdd = 0) { m_iToAdd = in_iToAdd; } void operator()(int& out_Int) { out_Int += m_iToAdd; } }; class A { public: std::vector < int > m_vData; void TraverseVector(TraveseFuncPtr in_func) { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; void main() { A tmp_a; tmp_a.m_vData.push_back(7); tmp_a.m_vData.push_back(5); tmp_a.m_vData.push_back(6); tmp_a.TraverseVector(Add7); // All ok. tmp_a.TraverseVector(AddNumber(13)); //C2664 } --- And thats it. error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)' No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called I tried to dig up STL source but hell the same for_each takes a CLASS (!) as a template parameter. No functions there. Who can say anything to this? Sincerely yours, Ilya Kalujny.
the definition of std::for_each template Function for_each (InputIterator first, InputIterator last, Function f) so, you can do this: // ======================================================= class A { public: std::vector m_vData; template // add this void TraverseVector(Function in_func) // ****** { for (int i = 0; i < m_vData.size(); i++) { (*in_func)(m_vData[i]); } } }; // =======================================================