Page 1 of 1
C++: Templates and member function pointers
Posted: Wed Feb 14, 2007 10:49 pm
by Alboin
Hello,
I have class DB:
Code: Select all
class DB {
protected:
map<int, string> List;
public:
template <class C>
void ForEach(void (C::*callback)(int id));
};
Now, this code has a list, or a database of sorts. When ForEach is called, the list needs to be shifted through and call the callback for each item. However, to use this throughout different classes, I should imagine I should have to use templates as to create typesafe callbacks. However, I am getting errors compiling this when called in main, as below:
(Note: MDB is a global instance of DB.)
Code: Select all
class test {
public:
void hi(int id) {
cout << "Hello " << id << "!" << endl;
}
test() {
MDB->ForEach<test>(hi);
}
};
int main(int argc, char *argv[]) {
test h;
}
Also, ForEach is defined as:
Code: Select all
void DB::ForEach(void (C::*callback)(int id)) {
/*Do the loop, etc... */
}
Finally, the error from gcc (Using gcc 4.? on Linux) is
Code: Select all
main.cc: In constructor ‘test::test()’:
main.cc:55: error: no matching function for call to ‘DB::ForEach(<unresolved overloaded function type>)’
Any help would be nice....This is an annoying problem that is probably something obvious ....Thanks!
Re: C++: Templates and member function pointers
Posted: Wed Feb 14, 2007 11:48 pm
by Colonel Kernel
Well, for one thing you are trying to use a C++ pointer-to-member function like a C# delegate -- that doesn't work. In C++, a pointer-to-member-function is a weird construct. It isn't really an address per se -- it contains just enough information to select the right method to call when an instance of that class is provided. Note that you have to provide the instance yourself, explicitly. When you pass "hi" to ForEach, "this" is not passed implicitly for you.
I'm nowhere near a C++ compiler right now, otherwise I'd try out a possible solution. What springs to mind is wrapping the instance and method together in an STL functor. Look up mem_fun or whatever it's called in the STL docs. It's defined in the <functional> header. In case you haven't heard of this technique, the way it works is basically by taking an object and method call such as o.m( x, y, z ) and wrapping it into a function object that overloads operator() so that you can call it like f( x, y, z ). A pointer or reference to the object o is stored inside the function object f.
Sorry if this is vague... I hope it helps...
Posted: Thu Feb 15, 2007 3:15 pm
by Alboin
mem_fun seems like it is what I need. However, I can't find anything about it other than how to use it with lists and such. (Even in Stroustrup's book.) Does anyone know how to incorporate it into my own functions and classes? Thanks!
Posted: Thu Feb 15, 2007 4:13 pm
by Colonel Kernel
Alboin wrote:mem_fun seems like it is what I need. However, I can't find anything about it other than how to use it with lists and such. (Even in Stroustrup's book.) Does anyone know how to incorporate it into my own functions and classes? Thanks!
Effective STL will be of some use. I don't know of a good online STL reference offhand... at least not one that actually explains how to use mem_fun (which is a bit arcane as it turns out).
You might also want to consider using boost::bind and/or boost::function (
www.boost.org).
Posted: Fri Feb 16, 2007 11:00 am
by Candy
Did you try taking the address of hi instead of just passing hi?
Posted: Fri Feb 16, 2007 3:25 pm
by Alboin
Edit:Check below.
Posted: Fri Feb 16, 2007 5:41 pm
by Alboin
Aye! I go it to compile.....Almost....It compiles, but does not yet link.....yup..
Anyway, this is what I've got now:
Code: Select all
class DB {
public:
template <class C>
void ForEach(C *inst, void (C::*callback)(int id));
};
template <class C>
void DB::ForEach(C *inst, void (C::*callback)(int id)) {
}
...
test() {
DB->ForEach<test>(this, &test::hi);
}
...
Yet, I get a link error....
Code: Select all
main.o: In function `test::test()':
main.cc:(.text._ZN4testC1Ev[test::test()]+0x31): undefined reference to `void DB::ForEach<test>(test*, void (test::*)(int))'
ForEach is clearly declared with templates and all; how is it not finding it? Any ideas?
Posted: Sat Feb 17, 2007 11:14 am
by Candy
Code: Select all
class DB {
public:
template <class C>
void ForEach(C *inst, void (C::*callback)(int id));
} MDB;
class test {
void hi(int id) {}
public:
test() {
MDB.ForEach<test>(this, &test::hi);
}
};
template <class C>
void DB::ForEach(C *inst, void (C::*callback)(int id)) {
}
int main() {
test obj;
}
That compiles, links and works here. Is this like what you're trying to do? If not, could you paste the full source so I can wreck it to work?
My guess is that the compiler can't instantiate the template because you don't specify the source for the function in the header file of the template. That's required (or you'd have to make it an export template which pretty few C++ compilers support).
Posted: Sat Feb 17, 2007 12:26 pm
by Alboin
Thanks, I hadn't realized that I had to put the source definition right in the header, but apparently that works because it now compiles. However, how do I call the callback?
Gives me this:
Code: Select all
DB.h:46: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘callback (...)’
Here's the current function:
Code: Select all
void ForEach(C *inst, void (C::*callback)(int id)) {
inst->*callback(id);
}
(This is why I tend to stick with just C....
)
Posted: Sat Feb 17, 2007 1:34 pm
by os64dev
loose the * in inst->*callback(id); inst->callback(id) should compile, i think
Posted: Sat Feb 17, 2007 2:27 pm
by Alboin
Okay. Got it.
Thanks for all your help!
Posted: Sat Feb 17, 2007 5:23 pm
by Candy
Alboin wrote:Okay. Got it.
Thanks for all your help!
Somebody making the C++ spec got the associativity of ->* and .* and operator() (apologies for the two ands, but using a comma would be more confusing) wrong, so you always have to use brackets around ->* and .* operations to make them work without it trying to call () on the object first, then dereferencing the target and calling it subsequently (or some other really odd order of events).