By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,079 Members | 901 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,079 IT Pros & Developers. It's quick & easy.

Problem using mem_fun.

P: n/a
I've got a function that I use a lot when making utility programs
that need to do the same thing to every directory in a tree.
Its prototype is:

unsigned long int CursDirs (void Func(void));

This just applies the fuction Func to every subdirectory of the
current directory. It works fine when I pass it pointers to regular
void-void functions.

But last night I had a situation where it would be very handy to pass
it a pointer to a member function of a class. This is in a program
that counts lines of text in all *.c, *.cpp, and *.h files in a
directory tree, starting at current directory and recursively descending.
(Basically, "line count of this project".) In this program, I have
this class:

class SourceTree
{
public:
SourceTree(void) : Lines(0UL) {}
void CountLines(void);
void PrintLines(void);
private:
void CountLinesInFile (const std::string& FileName);
void CountLinesInCurDir (void);
unsigned long int Lines;
};

I tried to pass &SourceTree::CountLinesInCurDir to CursDirs:

SourceTree::CountLines(void)
{
CursDirs(&SourceTree::CountLinesInCurDir);
return;
}

but OOPS, that's not allowed!

So I tried to use mem_fun from <functional> like this:

SourceTree::CountLines(void)
{
CursDirs(mem_fun(&SourceTree::CountLinesInCurDir)) ;
return;
}

But that doesn't work either. I get an error message saying
"cannot convert std::mem_fun_t<void, SourceTree> to void(*)()"

What am I doing wrong here? Is there a way to get mem_fun to
work in this application, or is this too far removed from it's
original intended purpose (ie, std. algorithms)?

(In the mean time, I had to copy&paste the entire body of CursDirs
into CountLines. This works, but is very messy. It'd sure be nice
to be able to do it in one line instead.)

--
Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant

Jul 22 '05 #1
Share this Question
Share on Google+
2 Replies


P: n/a

"Robbie Hatley" <lonewolfintj at pacbell dot net> wrote in message
news:41**********@127.0.0.1...
I've got a function that I use a lot when making utility programs
that need to do the same thing to every directory in a tree.
Its prototype is:

unsigned long int CursDirs (void Func(void));

This just applies the fuction Func to every subdirectory of the
current directory. It works fine when I pass it pointers to regular
void-void functions.

But last night I had a situation where it would be very handy to pass
it a pointer to a member function of a class. This is in a program
that counts lines of text in all *.c, *.cpp, and *.h files in a
directory tree, starting at current directory and recursively descending.
(Basically, "line count of this project".) In this program, I have
this class:

class SourceTree
{
public:
SourceTree(void) : Lines(0UL) {}
void CountLines(void);
void PrintLines(void);
private:
void CountLinesInFile (const std::string& FileName);
void CountLinesInCurDir (void);
unsigned long int Lines;
};

I tried to pass &SourceTree::CountLinesInCurDir to CursDirs:

SourceTree::CountLines(void)
{
CursDirs(&SourceTree::CountLinesInCurDir);
return;
}

but OOPS, that's not allowed!

So I tried to use mem_fun from <functional> like this:

SourceTree::CountLines(void)
{
CursDirs(mem_fun(&SourceTree::CountLinesInCurDir)) ;
return;
}

But that doesn't work either. I get an error message saying
"cannot convert std::mem_fun_t<void, SourceTree> to void(*)()"

What am I doing wrong here? Is there a way to get mem_fun to
work in this application, or is this too far removed from it's
original intended purpose (ie, std. algorithms)?


The return from mem_fun is a functor, not a function pointer. In any case
mem_fun doesn't help you in this particular case because you have no way to
pass the class itself into CurDirs.

You need a refresher course in functors.

The first thing you should do is rewrite CursDirs as a template so that it
can use either a function pointer or a functor.

template <class F>
unsigned long int CursDirs (F func)
{
...
func();
...
}

Then you should write your own functor that can call the member function you
want

struct LineCounter
{
LineCounter(SourceTree* tree) : _tree(tree) {}
void operator()() const
{
tree->CountLinesInCurDir();
}
private:
SourceTree* _tree;
};

Finally you use it like this

SourceTree::CountLines(void)
{
CursDirs(LineCounter(this));
}

This is untested code, but hopefully you get the idea.

john
Jul 22 '05 #2

P: n/a
Greetings, John Harrison. You wrote:
"Robbie Hatley" <lonewolfintj at pacbell dot net> wrote in message
news:41**********@127.0.0.1...
I've got a function that I use a lot when making utility programs
that need to do the same thing to every directory in a tree.
Its prototype is:

unsigned long int CursDirs (void Func(void));

This just applies the fuction Func to every subdirectory of the
current directory. It works fine when I pass it pointers to regular
void-void functions.

But last night I had a situation where it would be very handy to pass
it a pointer to a member function of a class. This is in a program
that counts lines of text in all *.c, *.cpp, and *.h files in a
directory tree, starting at current directory and recursively descending.
(Basically, "line count of this project".) In this program, I have
this class:

class SourceTree
{
public:
SourceTree(void) : Lines(0UL) {}
void CountLines(void);
void PrintLines(void);
private:
void CountLinesInFile (const std::string& FileName);
void CountLinesInCurDir (void);
unsigned long int Lines;
};

I tried to pass &SourceTree::CountLinesInCurDir to CursDirs:

SourceTree::CountLines(void)
{
CursDirs(&SourceTree::CountLinesInCurDir);
return;
}

but OOPS, that's not allowed!

So I tried to use mem_fun from <functional> like this:

SourceTree::CountLines(void)
{
CursDirs(mem_fun(&SourceTree::CountLinesInCurDir)) ;
return;
}

But that doesn't work either. I get an error message saying
"cannot convert std::mem_fun_t<void, SourceTree> to void(*)()"

What am I doing wrong here? Is there a way to get mem_fun to
work in this application, or is this too far removed from it's
original intended purpose (ie, std. algorithms)?

The return from mem_fun is a functor, not a function pointer. In any case
mem_fun doesn't help you in this particular case because you have no way to
pass the class itself into CurDirs.

Aye, I can see now, that is just the problem: CursDirs does not
have any way of calling CountLinesInCurDir through the "this"
pointer of the one and only SourceTree instance in my program.

You need a refresher course in functors.

The first thing you should do is rewrite CursDirs as a template so that it
can use either a function pointer or a functor.

template <class F>
unsigned long int CursDirs (F func)
{
...
func();
...
}

I did that, and it works fine. I can see how the template
parameter F makes func more "generic" so that CursDirs
will now work with either a function or a functor.

Thanks for the tip!

Then you should write your own functor that can call the member function you
want

struct LineCounter
{
LineCounter(SourceTree* tree) : _tree(tree) {}
void operator()() const
{
tree->CountLinesInCurDir();
}
private:
SourceTree* _tree;
};

Finally you use it like this

SourceTree::CountLines(void)
{
CursDirs(LineCounter(this));
}

This is untested code, but hopefully you get the idea.

john

Yes, that works very well! I actually put two such functors
in my program based around your "LineCounter", one to pass
a SourceTree member function to three "for_each" statements,
and the other to pass a SourceTree member function to CursDirs.

Perhaps I should try to templatize those as generic "Glue Functors".
Could be very useful for allowing functions and algorithms
to call member functions of types other than the argument type.

Thanks again for the help!
--
Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
Jul 22 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.