STL: container's values setup by another container

M

Maitre Bart

What I want to perform is calling a member function of container 1
(CRunner), using as argument the value of a container 2 (CNames). The
purpose is to transfer values from C2 into C1 using a specific C1 member
function. Both containers contains the same number of elements (or at least,
C1 is larger than C2).

As suggested by S. Meyers (and others), I would like to use an STL algorithm
instead of a custom loop. Let say I have the following:

class CRunner{
string m_name;
int m_order;

public:
bool SetOrder(int a_order) {m_order = a_order; return true;}
bool SetName(const string& a_name) {m_name = a_name; return true;}
};

vector<string> NameTable;
vector<CRunner> RunnerTable;

I created a template functor/function pair to be used in for_each():

template<class R, class T>
class mem_fun_iter_t : unary_function<T*, R>
{
public:
explicit mem_fun_iter_t(R (T::*p)(const T::iterator::value_type&),
vector<T>::iterator i) : pmf(p), iter(i) {}
R operator()(T* p) const {return (p->*pmf)(*iter++);}
private:
R (T::*pmf)(const T::iterator::value_type&);
vector<T>::iterator iter;
};

template<class R, class T>
inline static mem_fun_iter_t<R, T> mem_fun_iter(R (T::*p)(const
T::iterator::value_type&), vector<T>::iterator i)
{
return mem_fun_iter_t<R, T, vector<T> >(p, i);
}

(...unfortunetaly, I wasn't able to specify a generic parameter for
'vector', without getting all other kinds of errors...)

So that once both containers are initalized and filled, I can safely call:

for_each(NameTable.begin(), NameTable.end(), mem_fun_iter(CRunner::SetName,
RunnerTable.begin()));

But my compiler always generate this error:

[...] error C2784: 'mem_fun_iter_t<R,T> mem_fun_iter(R (T::*)(const
generic-type-264 &),generic-type-265)': could not deduce template argument
for '<Unknown>' from 'bool (RUNNER::*)(const string &)'

Is it my compiler (MSVS6) or is it a real deduction problem (missing
parameter)?
Is it a problem of algorithm? Is there any way to do the same with another
algorithm (such as transform(), etc.)?
Is there any way to reuse mem_fun* (with a binder or not) instead of the
above custom template functor/function pair?
Is there a way to make the call "end-of-container"-proof by using
back_inserter()?

I ask the those questions because I tried all those combinations without
success.
The task look simple, but caused me frustrations over the past 3 days.

As a second part, what would be the implications if rather than having
'vector<string> NameTable' I had:

vector<CNames> NameTable;

with:

class CNames
{
//...
public:
string GetName();
//...
};

Thanks for helping.
 
A

Andreas Müller

Maitre Bart said:
What I want to perform is calling a member function of container 1
(CRunner), using as argument the value of a container 2 (CNames). The
purpose is to transfer values from C2 into C1 using a specific C1 member
function. Both containers contains the same number of elements (or at least,
C1 is larger than C2).

As suggested by S. Meyers (and others), I would like to use an STL algorithm
instead of a custom loop.

<snip/>


IMHO it would be ok to use std::transform. You can either use it to collect
the results of the function calls, or just ignore the results:

#include <vector>
#include <string>
#include <algorithm>
#include <functional>
struct Xox
{
bool Foo(const std::string& s)
{
std::cout << "Foo( " + s + ")" << std::endl;
return s.size()>3;
}
};
// an iterator that just eats everything up
template<class CONTAINER>
struct dummy_insert_iterator
{
dummy_insert_iterator<CONTAINER>& operator++(){ return *this; }
dummy_insert_iterator<CONTAINER> operator++(int){ return *this; }
dummy_insert_iterator<CONTAINER>& operator*(){ return *this; }
dummy_insert_iterator<CONTAINER>& operator=(
typename CONTAINER::const_reference Val){return *this;}
};
template<class CONTAINER> inline
dummy_insert_iterator<CONTAINER> black_hole_back_inserter(const
CONTAINER&)
{
return dummy_insert_iterator<CONTAINER>();
}
int main()
{
std::vector<Xox> x;
x.push_back(Xox());
x.push_back(Xox());
std::vector<std::string> s;
s.push_back("tst1");
s.push_back("t2");
// ... variant 1: collect results
std::vector<bool> res;
std::transform(x.begin(), x.end(), s.begin(), std::back_inserter(res),
std::mem_fun_ref(Xox::Foo)
);
// ... variant 2: don't care for results:
std::transform(x.begin(), x.end(), s.begin(),
black_hole_back_inserter(res),
std::mem_fun_ref(Xox::Foo)
);
return 0;
}

HTH,
Andy
 
M

Maitre Bart

Andreas Müller said:
<snip/>


IMHO it would be ok to use std::transform. You can either use it to collect
the results of the function calls, or just ignore the results:

#include <vector>
#include <string>
#include <algorithm>
#include <functional>
struct Xox
{
bool Foo(const std::string& s)
{
std::cout << "Foo( " + s + ")" << std::endl;
return s.size()>3;
}
};
// an iterator that just eats everything up
template<class CONTAINER>
struct dummy_insert_iterator
{
dummy_insert_iterator<CONTAINER>& operator++(){ return *this; }
dummy_insert_iterator<CONTAINER> operator++(int){ return *this; }
dummy_insert_iterator<CONTAINER>& operator*(){ return *this; }
dummy_insert_iterator<CONTAINER>& operator=(
typename CONTAINER::const_reference Val){return *this;}
};
template<class CONTAINER> inline
dummy_insert_iterator<CONTAINER> black_hole_back_inserter(const
CONTAINER&)
{
return dummy_insert_iterator<CONTAINER>();
}
int main()
{
std::vector<Xox> x;
x.push_back(Xox());
x.push_back(Xox());
std::vector<std::string> s;
s.push_back("tst1");
s.push_back("t2");
// ... variant 1: collect results
std::vector<bool> res;
std::transform(x.begin(), x.end(), s.begin(), std::back_inserter(res),
std::mem_fun_ref(Xox::Foo)

In fact, "std::mem_fun1_ref" worked on my side.
);
// ... variant 2: don't care for results:
std::transform(x.begin(), x.end(), s.begin(),
black_hole_back_inserter(res),
std::mem_fun_ref(Xox::Foo)
);
return 0;
}

HTH,
Andy

Thanks for your precious help.

BTW, did you get experienced by yourself with this stuf, or did you read a
good book on putting in practice stl algorithms?
 

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,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top