for_each and member function

  • Thread starter Przemyslaw Koprowski
  • Start date
P

Przemyslaw Koprowski

Hi all,

I have the following problem: take a class
that is intended to interpret strings char_by_char
depending on its internal state (that changes during
the interpretation) i.e. something like a finite_state_machine
(not quite but close).
The class has a member that interprets a single char ('doit'
in the example code below) and a member to intrepret a whole
string calling the previous one for each character.
The question is: can the later member use for_each template?
If so, how to pass the former method as the one to be called
on each char?

Here is a simple example:

#include <string>

class interp {
private:
// some internal state, e.g
int x, y;
public:
// c-tor sets-up initial state e.g.
interp() : x(0), y(0) {};
// members to interpret chars/strings
void doit(char);
void doit(const std::string &s);
// ...
};

void interp::doit(char c)
{
// interpret c and do sth. depending on
// internal state, possibly change the state
// e.g.
switch( c ) {
case '+' : x += y; break;
case '-' : y += 7; break;
// ...
}
}

void interp::doit(const std::string &s)
{
// interpret the string char by char
std::for_each(
s.begin(),
s.end(),
doit // ERROR
);
}

int main()
{
interp C;

C.doit("+-0");
return 0;
}

The marked line causes an error since the name 'doit'
is ambigious (that's the first problem how to resolve
the ambiguity). Even if I change the names of the two
methods (say 'doit1', 'doit2') it doesn't help, as this
is still a member function not a "regular" one.

Notice that mem_fun adaptor doesn't help here (at least
directly) since I don't want to call a member of each
element in the collection (being char and so not having
any members). Rather I want to call a member of different
class.

Thanks in advance,
Przemek

P.S.
I can very easily do it with explicit loop (and it is a way
how I do it rigth now). The question is whether it can be
done *without* explicit loop.
 
D

Daniel T.

Przemyslaw Koprowski said:
I have the following problem: take a class that is intended to
interpret strings char_by_char depending on its internal state
(that changes during the interpretation) i.e. something like a
finite_state_machine (not quite but close).
The class has a member that interprets a single char ('doit' in the
example code below) and a member to intrepret a whole string
calling the previous one for each character. The question is: can
the later member use for_each template?

Not if both member functions have the same name, otherwise yes.
If so, how to pass the former method as the one to be called
on each char?

void interp::doit(const std::string &s)
{
for_each( s.begin(), s.end(),
bind1st( mem_fun( &interp::doit ), this ) );
}

The above won't work however because the template system doesn't know
which "doit" to use. So:

class interp {
public:
void dochar( char );
void dostring( const string& );
};

with the above dostring can be implemented as follows:

void interp::dostring(const std::string &s)
{
for_each( s.begin(), s.end(),
bind1st( mem_fun( &interp::dochar ), this ) );
}

or if using the boost lambda library...

for_each( s.begin(), s.end(), bind( &interp::dochar, this, _1 ) );
 
K

kwikius

Not if both member functions have the same name, otherwise yes.

FWIW You can use a cast to get the correct function:

void interp::doit(const std::string & s)
{
// interpret the string char by char

typedef void (interp::*mfp)(char);

std::for_each(
s.begin(), s.end(),
std::bind1st(
std::mem_fun(
mfp(&interp::doit) //<-- explict cast
),
this
)
);
}
 
K

kwikius

void interp::doit(const std::string & s)
{
// interpret the string char by char

   typedef void (interp::*mfp)(char);

   std::for_each(
    s.begin(), s.end(),
    std::bind1st(
     std::mem_fun(
       mfp(&interp::doit) //<-- explict cast
     ),
       this
     )
   );

hmm.. maybe that could be wrapped up to make it easier to read, though
you may end up having various overloads...

template <typename T, typename R, typename A>
struct this_fun_binder1{

typedef std::mem_fun1_t<R,T,A> mem_fun;

typedef std::binder1st<mem_fun> type;

};

template <typename T, typename R, typename A>
typename this_fun_binder1<T,R,A>::type
this_fun(T *t, R(T::*f)(A))
{
return std::bind1st( std::mem_fun( f ),t );
};


//.......

void interp::doit(const std::string & s)
{
typedef void (interp::*mfp)(char);
std::for_each(
s.begin(), s.end(),
this_fun(this,mfp(&interp::doit))
);
}

.. which is IMO nicer to read.

regards
Andy Little
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top