-
How to pair/multimap <int, pointer to a function>?
Could someone help with the correct syntax? I tried something like
Code:
class myclass {
multimap<int, void(*)()> mm_fn;
...
void afunction();
...
void anotherfunction(int anint){
mm_fn.insert(pair<int,void(*)()>(anint,afunction));
}
}
and the compiler does not like it. Thanks!
-
Re: How to pair/multimap <int, pointer to a function>?
C++ class methods are not compatible with C-style function pointers (at least, not without special syntax), because they have an additional hidden parameter "this".
I recommend you use std::function, which can handle a class method with the help of std::bind, instead of a function pointer if your compiler supports it. If not, boost::function and boost::bind have approximately equivalent behavior.
Another option is to make afunction() static, and add the object pointer ("this") as an explicit parameter if necessary. (If it isn't necessary, then perhaps afunction should have been static anyway.)
-
Re: How to pair/multimap <int, pointer to a function>?
-
Re: How to pair/multimap <int, pointer to a function>?
It's seldom the proper thing to do but you can always "bypass the type system". You see it in very low-level C-style code that has to be very general.
Code:
void afunction() {
std::cout << "hello" << std::endl;
}
std::unordered_multimap<int, void*> mm_fn;
//
int aint = 13;
mm_fn.insert(std::make_pair(aint, reinterpret_cast<void*>(&afunction)));
void(*foo)();
foo = reinterpret_cast<void(*)()>(mm_fn.find(aint)->second);
foo();
void* is a pointer to anything really (for example it's what malloc returns). You need to cast it to and back from the wanted type and for that you use reinterpret_cast.
Assuming this is for high performance purposes, unordered_multimap is faster than multimap. make_pair is for convenience.
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
nuzzle
It's seldom the proper thing to do but you can always "bypass the type system". You find it in very low-level C-style code that has to be very general.
http://www.parashift.com/c++-faq-lit...html#faq-33.10
http://www.parashift.com/c++-faq-lit...html#faq-33.11
Regards,
Paul McKenzie
-
Re: How to pair/multimap <int, pointer to a function>?
A more C++ way to approach what you want, that doesn't require you to bypass the type system, would be to store a map of pointers to function objects instead. The derived function objects classes can either implement the functionality or act as wrappers around other class methods or static functions.
Maybe this could be something like you are trying to implement.
Code:
#include <iostream>
#include <map>
#include <algorithm>
//**** Base ****
struct FunctionObject
{
virtual void operator ()() = 0;
};
//**** Function object ****
struct F1 : public FunctionObject
{
void operator ()()
{
std::cout << "F1 operator ()\n";
}
};
//**** Wrapper for class member function ****
struct SomeStruct
{
void MemberFunction()
{
std::cout << "Member Function\n";
}
} someStruct;
struct F2 : public FunctionObject
{
void operator ()()
{
someStruct.MemberFunction();
}
};
//**** Wrapper for static function ****
void SomeStaticFunction()
{
std::cout << "Some Static Function\n";
}
struct F3 : public FunctionObject
{
void operator ()()
{
SomeStaticFunction();
}
};
int main()
{
// The function objects.
F1 f1;
F2 f2;
F3 f3;
// The map.
std::map<int, FunctionObject*> mm_fn;
mm_fn[1] = &f1;
mm_fn[2] = &f2;
mm_fn[3] = &f3;
// Iterate and call.
std::map<int, FunctionObject*>::iterator itr = mm_fn.begin();
while (itr != mm_fn.end())
{
// Get the function object.
FunctionObject& functionObject = *itr->second;
// Call it.
functionObject();
++itr;
}
return 0;
}
-
Re: How to pair/multimap <int, pointer to a function>?
Thank you everyone! Following Lindley's suggestions I changed the code to
Code:
class myclass {
multimap<int, mem_fun_t<void, myclass > > mm_fn;
...
void afunction();
...
void anotherfunction(int anint){
mm_fn.insert(pair<int, mem_fun_t<void, myclass > >(anint, mem_fun(&myclass::afunction)));
}
}
Now the compiler does not complain but I am not sure if this is legal or will work as intended (please see paragraph below).
What I would like to do is to build a multimap at run time. In the beginning the program reads in a file telling it which integer points to which member function. One integer may point to one or more member functions. A multimap is built according to the file content. After that the program receives integer input and calls the corresponding member function(s) in the multimap. (I haven't got to this part - not sure if I am on the right track yet.)
Please help. Thanks!
-
Re: How to pair/multimap <int, pointer to a function>?
JohnW@Wessex, your suggestion is basically the same as std::function except more home-grown.
Quote:
What I would like to do is to build a multimap at run time. In the beginning the program reads in a file telling it which integer points to which member function. One integer may point to one or more member functions. A multimap is built according to the file content. After that the program receives integer input and calls the corresponding member function(s) in the multimap. (I haven't got to this part - not sure if I am on the right track yet.)
The key question you have not addressed is----call the member function of which object?
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
Lindley
JohnW@Wessex, your suggestion is basically the same as std::function except more home-grown.
Ah, interesting.
I've not had the opportunity to use a compiler that supports std::function yet. :(
-
Re: How to pair/multimap <int, pointer to a function>?
Think of it as a generic function object. You can assign any functor or function pointer to it, so long as it matches the arguments and return type specified in the template. In C++03, many STL functions support arbitrary functors/function pointers, but they do it by making the type a template argument. That works fine for "one call" usage, but when you want to store these things in a container for later, it is insufficient. std::function fills that gap.
std::bind is a generalization of std::bind1st and std::mem_fun, etc in C++03. It can bind any number of arguments to any number of function or functor parameters, including binding the "this" to a member method, and return an appropriate functor. (In practice, some implementations of std::bind still have limits on the number of bindings. Variadic templates should eliminate this limitation when they are better supported.)
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
acppdummy
What I would like to do is to build a multimap at run time. In the beginning the program reads in a file telling it which integer points to which member function. One integer may point to one or more member functions.
OK. Given this, do you know the syntax to call a non-static member function using a pointer? It is far different than making "normal" non-static member function calls via pointer, which is the point Lindley made.
You need an object in the call syntax. Without it, your design needs to be redone.
Regards,
Paul McKenzie
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
Lindley
It can bind [...] including binding the "this" to a member method, and return an appropriate functor
note that an std::function plus a lambda capture is better suited for this purpose, being the former required to store the 'this' pointer internally in the function object instead of invoking the heap; AFAIK, this guarantee doesn't hold for std::bind.
-
Re: How to pair/multimap <int, pointer to a function>?
Some implementations of lambdas (VS10, I think) doesn't handle the capture of "this" properly just yet. You can get around it by assigning this to a local pointer before the lambda.
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
Lindley
...
The key question you have not addressed is----call the member function of which object?
Sorry. I was thinking something like this:
Code:
myclass mc;
mc.readfileandmakemultimap();
// get integer input and call corresponding mc.fun1() mc.fun2() etc.
// not sure how to do it though
Quote:
Originally Posted by
Paul McKenzie
OK. Given this, do you know the syntax to call a non-static member function using a pointer? It is far different than making "normal" non-static member function calls via pointer, which is the point Lindley made.
I don't know. Any suggestions? Thanks!
Quote:
You need an object in the call syntax. Without it, your design needs to be redone.
I won't mind redoing if I know how to. Any suggestion on how exactly to redo it is welcome. Thanks!
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
acppdummy
I don't know.
Then that's a problem.
Code:
class MyObject
{
public:
int SomeFunc(int);
};
typedef int (MyObject::*fn)(int);
int main()
{
fn MyFnPtr = &MyObject::SomeFunc;
MyObject object; // create an instance of MyObject
(object.*MyFnPtr)(10);
}
Look at the line in red. You see that the object instance must be part of the syntax to call a non-static member function. If you were thinking it would look like your 'C' function call syntax, you were wrong.
Code:
typedef int (*fn)(int);
int SomeFunc(int);
int main()
{
fn MyFnPtr = &SomeFunc;
(*fn)(10); // C-style function
}
Note the vast difference.
So where is "object" in your multimap design going to come from?
Regards,
Paul McKenzie
-
Re: How to pair/multimap <int, pointer to a function>?
Thanks! Now it's clearer to me. So I should move the multimap outside of the class and after an object of that class is created, right?
-
Re: How to pair/multimap <int, pointer to a function>?
Quote:
Originally Posted by
acppdummy
Thanks! Now it's clearer to me. So I should move the multimap outside of the class and after an object of that class is created, right?
The bottom line is that you need an object created to call non-static member functions, whether or not you're calling the function using a pointer. That's just basic C++.
Code:
class X
{
public:
void DoSomething();
};
int main()
{
// how do you call DoSomething()?
// not like this:
// X::DoSomething();
//...
// like this -- create an object...
X someObject;
someObject.DoSomething();
}
So a pointer to the non-static member function has to follow the same rules, thus the syntax I showed you earlier.
Regards,
Paul McKenzie
-
Re: How to pair/multimap <int, pointer to a function>?
Understood. Thank you very much!
-
Re: How to pair/multimap <int, pointer to a function>?
OK I hope I am getting close to the right track: failed to find the syntax to call std::mem_fun and confused by std::function and std::bind, I found this:
http://www.goingware.com/tips/member-pointers.html
Quote:
... One of the best uses for member function pointers is caching the outcome of a decision over which of several member functions should be called in a particular circumstance. If a decision is always going to yield the same result, then it may be faster and even cleaner to make the decision just once ahead of time, then store the outcome in the form of a member function pointer. This is especially advantageous when the decision will be made repeatedly in a loop. ...
This is exactly what I needed! The example code follows:
Code:
#include <exception>
class Test {
public:
Test( long inFactor );
long TimesOne( long inToMultiply ) const;
long TimesTwo( long inToMultiply ) const;
long TimesThree( long inToMultiply ) const;
long MultiplyIt( long inToMultiply ) const;
private:
typedef long (Test::*Multiplier)( long inToMultiply ) const;
long mFactor;
Multiplier mMultFuncPtr;
static Multiplier GetFunctionPointer( long inFactor ); };
Test::Test( long inFactor )
: mFactor( inFactor ),
mMultFuncPtr( GetFunctionPointer( mFactor ) ) {
return; }
Test::Multiplier Test::GetFunctionPointer( long inFactor ) {
switch ( inFactor ){
// Decision only made once!
case 1:
return &Test::TimesOne;
break;
case 2:
return &Test::TimesTwo;
break;
case 3:
return &Test::TimesThree;
break;
default:
throw std::exception(); } }
long Test::MultiplyIt( long inToMultiply ) const {
// Using cached decision result
return (this->*mMultFuncPtr)( inToMultiply ); }
void MultiplyThem( long inFactor ) {
Test myTest( 2 );
long product;
for ( long i = 0; i < 1000000; ++i )
product = myTest.MultiplyIt( i ); }
Then I found this:
http://www.codeguru.com/cpp/cpp/arti...r-Function.htm
Quote:
... An important application of pointer-to-member functions is to generate the response events according to inputs. ...
Again exactly what I am trying to do! The example code follows:
Code:
- #include <stdio.h>
- #include <string>
- #include <iostream>
- class Printer{//An abstract printing machine
- public:
- void Copy(char * buff, const char * source){//copy the file
- strcpy(buff, source);
- }
- void Append(char * buff, const char * source){//extend the file
- strcat(buff, source);
- }
- };
- enum OPTIONS { COPY, APPEND };//two possible commands in the menu.
- typedef void(Printer::*PTR) (char*, const char*);//pointer-to-member function
- void working(OPTIONS option,
- Printer* machine,
- char* buff,
- const char* infostr){
- PTR pmf[2]= {&Printer::Copy, &Printer::Append}; //pointer array
- switch (option){
- case COPY:
- (machine->*pmf[COPY])(buff, infostr);
- break;
- case APPEND:
- (machine->*pmf[APPEND])(buff, infostr);
- break;
- }
- }
- int main(){
- OPTIONS option;
- Printer machine;
- char buff[40];//target
- working(COPY, &machine, buff, "Strings ");
- working(APPEND, &machine, buff, "are concatenated! ");
- std::cout<<buff<<std::endl;
- }
- Output:
- Strings are concatenated!
Following the two examples I put together something like this:
Code:
class MyClass {
...
int map_formula(int id, ...);
...
void fna();
void fnb();
...
void run(int id, ...);
...
}
typedef void(MyClass::*memfnptr_t) ();//pointer-to-member function
multimap<int, memfnptr_t> mm_id_fn;
int MyClass::map_formula(int id, ...){
// will be called multiple times with different values of id to construct the multimap
...
mm_id_fn.insert(pair<int,memfnptr_t>(id,&MyClass::fna));
...
mm_id_fn.insert(pair<int,memfnptr_t>(id,&MyClass::fnb));
...
}
void MyClass::run(int id, ...){
multimap<int,memfnptr_t>::iterator it;
pair<multimap<int,memfnptr_t>::iterator, multimap<int,memfnptr_t>::iterator> ret;
it = mm_id_fn.find(id);
if (it!=mm_id_fn.end()){
ret = mm_id_fn.equal_range(id); // find all functions pointed by id
for (it = ret.first; it != ret.second; ++it){
memfnptr_t fn=(*it).second;
(this->*fn)();
}
cout << endl;
}
}
It compiles and seems to run OK but I am not sure if it is legal or correct. Please comment. Thanks!
-
Re: How to pair/multimap <int, pointer to a function>?
I have to move the multimap back into the class otherwise different instances of the class share the same multimap and interfere with one another. Now the code looks something like
Code:
class MyClass;
typedef void(MyClass::*memfnptr_t) ();//pointer-to-member function
class MyClass {
...
multimap<int, memfnptr_t> mm_id_fn;
...
int map_formula(int id, ...);
...
void fna();
void fnb();
...
void run(int id, ...);
...
}
... // the rest is the same as before
It seems to work so far. Please comment if there is anything wrong with this approach. Also I wonder if the typedef can be hidden inside the class as well? Thanks!