pointer_protector template

J

jsnX

say i have a function object silly that takes a const ref to clowns

class silly : public std::unary_function<const clown&, bool>
{
...
}

and then i decide to feed it a bunch of pointers to clowns:

for_each(clown_pointers.begin(), clown_pointers.end(), silly());

of course this doesn't work. i would like some magic template that
makes it work like this:

for_each(clown_pointers.begin(), clown_pointers.end(),
pointer_protector(silly()));

so actually pointer_protector would be an overloaded function template,
which knows to check for whether or not it's getting a
std::unary_function<> or a std::binary_function<>, and then it would
spit out a corresponding unary pointer protector or binary pointer
protector. for the rest of this discussion, i will stick t talking
about the unary pointer protector and leave the binary pointer
protector as an exercise. here is my unary pointer protector template:

template<typename Arg, typename Res>
class unary : public std::unary_function<Arg*, Res>
{
public:

unary(const std::unary_function<Arg, Res>& f) : f(f)
{}

Res
operator() (Arg* a) //27
{ //28
return f(*a); //29
} //30
//31
private:
std::unary_function<Arg, Res> f;
};

this does not work - when i create a function object and encapsulate in
a pointer protector like this:

struct print_it : public std::unary_function<int, int>
{
...
}

int
main()
{
for_each( foo.begin(), foo.end(),
unary<print_it::argument_type,
print_it::result_type>(print_it()) );
}

i get an error like this:

unary.cpp:29 error: no match for call to `(unary_function<int, int>)
(int &)'

using g++ via gfilt on FreeBSD 5.4-STABLE. so what is the right way to
write a pointer to reference encapsulating translator? does it already
exist?
 
M

Matthias Kaeppler

jsnX said:
using g++ via gfilt on FreeBSD 5.4-STABLE. so what is the right way to
write a pointer to reference encapsulating translator? does it already
exist?

Yes, for example you can use boost::lambda (check www.boost.org). It
implements the lambda calculus and is capable of creating these functors
for you automatically. Check their examples.

Another option would be to create two templates for your functor using
partial specialization: One working on pure objects and one working on
pointers to objects.
You can use boost::type_traits to check whether it's a pointer type or
not and then let the compiler instantiate the correct template
automagically.
 
M

Matthias Kaeppler

jsnX said:
I would really like to know why my code does not work.

The code you posted was more than incomplete. Please post your real
code, so we can take a look at it.

One "solution" not using boost or related would be to set flags and then
utilize template specialization to produce functors with different behavior.

//-----

template <bool is_pointer, bool is_binary>
struct silly: unary_function<const clown&, bool> {
bool operator() (const clown& arg) {}
};

template <true, false>
struct silly: unary_function<const clown*, bool> {
bool operator() (const clown* arg) {}
};

template <false, true>
struct silly: binary_function<const clown&, const clown&, bool> {
bool operator() (const clown& arg1, const clown& arg2) {}
};

template <true, true>
struct silly: binary_function<const clown*, const clown*, bool> {
bool operator() (const clown* arg1, const clown* arg2) {}
};

//-----

You can then feed it to STL algos using the same name, but you have to
provide the template arguments. For example, if you have a collection
coll which holds pointers to clown objects, you can do something like this:

for_each(coll.begin(), coll.end(), silly<true, false>());

Is that what you mean?
 
J

jsnX

my real code is this:

===========test.cpp============

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <utility>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <map>


struct print_it : public std::unary_function<int, int>
{
int
operator() (int i)
{
std::cout << i << " " << std::endl;
return i;
}
};

template<typename Arg, typename Res>
class unary : public std::unary_function<Arg*, Res>
{
public:

unary(const std::unary_function<Arg, Res>& f) : f(f)
{}

Res
operator() (Arg* a)
{
return f(*a); //35
}

private:
std::unary_function<Arg, Res> f;
};


int
main(int argc, char* argv[])
{
using namespace std;

vector<int*> foo;

cout << "foo [ ";
for(int i = 0; i < 10; i++)
{
int* kittens = new int(rand() % 32);
cout << *kittens << " ";
foo.push_back(kittens);
}
cout << "]" << endl;

cout << "foo [ ";
for_each( foo.begin(), foo.end(),
unary< print_it::argument_type,
print_it::result_type >(print_it()) ); //62
cout << "]" << endl;


exit(0);
}

===================================

and it fails like this:

===================================
test.cpp: In member function `int unary<int, int>::eek:perator()(int *)':
stl_algo.h:158: instantiated from
`unary<
int, int
> for_each(
vector<int *>::iterator, vector<int *>::iterator, unary<int,
int>
)'
test.cpp:62: instantiated from here
test.cpp:35: error: no match for call to `(unary_function<int, int>)
(int &)'
===================================
 
T

Tobias Blomkvist

jsnX said:
my real code is this:

===========test.cpp============

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <utility>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <map>


struct print_it : public std::unary_function<int, int>
{
int
operator() (int i)
{
std::cout << i << " " << std::endl;
return i;
}
};

template<typename Arg, typename Res>
class unary : public std::unary_function<Arg*, Res>
{
public:

unary(const std::unary_function<Arg, Res>& f) : f(f)
{}

Res
operator() (Arg* a)
{
return f(*a); //35
}

private:
std::unary_function<Arg, Res> f;
};

Try

template<typename Arg, typename Res, typename Function>
class unary : public std::unary_function<Arg*, Res>
{
public:

unary(const Function& f) : f(f)
{}

Res
operator() (Arg* a)
{
return f(*a); //35
}

private:
Function f;
};

Why? unary_function does not include an operator() which you are
trying to use. unary_function just contain traits information.

Which basically means you can deduce Arg and Res from Function
Function::result_type operator()typename Function::argument_type* a);

for_each( foo.begin(), foo.end(),
unary< print_it::argument_type,
print_it::result_type,print_it >(print_it()) );

Or
for_each( foo.begin(), foo.end(),
unary< print_it >(print_it()) );

If you just use typename Function in the template definition
template<typename Function>
class unary : public std::unary_function< typename
Function::argument_type *, typename Function::result_type>

Tobias
 
T

Tobias Blomkvist

Tobias said:
Which basically means you can deduce Arg and Res from Function
Function::result_type operator()typename Function::argument_type* a);

typename Function::result_type operator()
(typename Function::argument_type * a);
for_each( foo.begin(), foo.end(),
unary< print_it::argument_type,
print_it::result_type,print_it >(print_it()) );

Since in this case unary knows what function object it will recieve,
you could replace it with: (constructor argument not needed)

unary<print_it>()(7);

Tobias
 
J

jsnX

Since in this case unary knows what function object it
will recieve, you could replace it with:
(constructor argument not needed)

unary<print_it>()(7);

If I pass in '7' as in your example above, won't it get read as a
pointer and make the code puke at runtime?
 
T

Tobias Blomkvist

jsnX sade:
If I pass in '7' as in your example above, won't it get read as a
pointer and make the code puke at runtime?

Yeah, ignore that last statement.

Tobias
 
J

jsnX

so basically, it works. here's the source that i'm working with now:

==============deref.cpp====================
#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <utility>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <map>

namespace deref
{

template<class F>
class unary_function
: public std::unary_function< typename F::argument_type*,
typename F::result_type >
{
public:

unary_function(const F& f) : f(f)
{}

typename F::result_type
operator() (typename F::argument_type* a)
{
return f(*a);
}

private:
F f;
};

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< std::unary_function<Arg, Res> >(f);
}


template<class F>
class binary_function
: public std::binary_function< typename F::first_argument_type*,
typename F::second_argument_type*,
typename F::result_type >
{
public:

binary_function(const F& f) : f(f)
{}

typename F::result_type
operator() ( typename F::first_argument_type* _1,
typename F::second_argument_type* _2 )
{
return f(*_1, *_2);
}

private:
F f;
};

template<typename Arg_1, typename Arg_2, typename Res>
binary_function< std::binary_function<Arg_1, Arg_2, Res> >
create(const std::binary_function<Arg_1, Arg_2, Res>& f)
{
return binary_function said:
}

}
=======================================

====================test.cpp==============
#include "deref.cpp"


struct print_it : public std::unary_function<int, int>
{
int
operator() (int i)
{
std::cout << i << " ";
return i;
}
};

int
main(int argc, char* argv[])
{
using namespace std;

vector<int*> foo;

cout << "foo [ ";
for(int i = 0; i < 10; i++)
{
int* kittens = new int(rand() % 32);
cout << *kittens << " ";
foo.push_back(kittens);
}
cout << "]" << endl;

cout << "foo [ ";
for_each( foo.begin(), foo.end(),
deref::unary_function<print_it>(print_it()) );
cout << "]" << endl;


exit(0);
}
=======================================

The two deref::create(...) functions in deref.cpp don't do what I would
like, however. When I try this call for the for_each statement:

for_each( foo.begin(), foo.end(),
deref::create(print_it()) );

i get the error that goes

no match for call to `(unary_function<int, int>) (int &)'

which i guess is because my print_it object gets cast to
std::unary_function when it enters my create function, and then the
deref::unary_function object is instantiated with a std::unary_function
object and not a print_it object! Is there a way to rewrite
deref::create sort of like this:

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< std::unary_function<Arg, Res> >(f);
}


template<class F>
class binary_function
: public std::binary_function< typename F::first_argument_type*,
typename F::second_argument_type*,
typename F::result_type >
{
public:

binary_function(const F& f) : f(f)
{}

typename F::result_type
operator() ( typename F::first_argument_type* _1,
typename F::second_argument_type* _2 )
{
return f(*_1, *_2);
}

private:
F f;
};

template<typename Arg_1, typename Arg_2, typename Res>
binary_function< std::binary_function<Arg_1, Arg_2, Res> >
create(const std::binary_function<Arg_1, Arg_2, Res>& f)
{
return binary_function said:
}

}
=======================================

====================test.cpp==============
#include "deref.cpp"


struct print_it : public std::unary_function<int, int>
{
int
operator() (int i)
{
std::cout << i << " ";
return i;
}
};

int
main(int argc, char* argv[])
{
using namespace std;

vector<int*> foo;

cout << "foo [ ";
for(int i = 0; i < 10; i++)
{
int* kittens = new int(rand() % 32);
cout << *kittens << " ";
foo.push_back(kittens);
}
cout << "]" << endl;

cout << "foo [ ";
for_each( foo.begin(), foo.end(),
deref::unary_function<print_it>(print_it()) );
cout << "]" << endl;


exit(0);
}
=======================================

The two deref::create(...) functions in deref.cpp don't do what I would
like, however. When I try this call for the for_each statement:

for_each( foo.begin(), foo.end(),
deref::create(print_it()) );

i get the error that goes

no match for call to `(unary_function<int, int>) (int &)'

which i guess is because my print_it object gets cast to
std::unary_function when it enters my create function, and then the
deref::unary_function object is instantiated with a std::unary_function
object and not a print_it object! Is there a way to rewrite
deref::create sort of like this:

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< std::unary_function<Arg, Res> >(f);
}


template<class F>
class binary_function
: public std::binary_function< typename F::first_argument_type*,
typename F::second_argument_type*,
typename F::result_type >
{
public:

binary_function(const F& f) : f(f)
{}

typename F::result_type
operator() ( typename F::first_argument_type* _1,
typename F::second_argument_type* _2 )
{
return f(*_1, *_2);
}

private:
F f;
};

template<typename Arg_1, typename Arg_2, typename Res>
binary_function< std::binary_function<Arg_1, Arg_2, Res> >
create(const std::binary_function<Arg_1, Arg_2, Res>& f)
{
return binary_function said:
}

}
=======================================

====================test.cpp==============
#include "deref.cpp"


struct print_it : public std::unary_function<int, int>
{
int
operator() (int i)
{
std::cout << i << " ";
return i;
}
};

int
main(int argc, char* argv[])
{
using namespace std;

vector<int*> foo;

cout << "foo [ ";
for(int i = 0; i < 10; i++)
{
int* kittens = new int(rand() % 32);
cout << *kittens << " ";
foo.push_back(kittens);
}
cout << "]" << endl;

cout << "foo [ ";
for_each( foo.begin(), foo.end(),
deref::unary_function<print_it>(print_it()) );
cout << "]" << endl;


exit(0);
}
=======================================

The two deref::create(...) functions in deref.cpp don't do what I would
like, however. When I try this call for the for_each statement:

for_each( foo.begin(), foo.end(),
deref::create(print_it()) );

i get the error that goes

no match for call to `(unary_function<int, int>) (int &)'

which i guess is because my print_it object gets cast to
std::unary_function when it enters my create function, and then the
deref::unary_function object is instantiated with a std::unary_function
object and not a print_it object! Is there a way to rewrite
deref::create sort of like this:

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< what_so_ever_f_is >(f);
}
 
J

jsnX

so basically, it works. here's the source that i'm working with now:

==============deref.cpp====================
#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <utility>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <map>

namespace deref
{

template<class F>
class unary_function
: public std::unary_function< typename F::argument_type*,
typename F::result_type >
{
public:

unary_function(const F& f) : f(f)
{}

typename F::result_type
operator() (typename F::argument_type* a)
{
return f(*a);
}

private:
F f;
};

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< std::unary_function<Arg, Res> >(f);
}

template<class F>
class binary_function
: public std::binary_function< typename F::first_argument_type*,
typename F::second_argument_type*,
typename F::result_type >
{
public:

binary_function(const F& f) : f(f)
{}

typename F::result_type
operator() ( typename F::first_argument_type* _1,
typename F::second_argument_type* _2 )
{
return f(*_1, *_2);
}

private:
F f;
};

template<typename Arg_1, typename Arg_2, typename Res>
binary_function< std::binary_function<Arg_1, Arg_2, Res> >
create(const std::binary_function<Arg_1, Arg_2, Res>& f)
{
return binary_function said:

}

}

=======================================

====================test.cpp==============
#include "deref.cpp"

struct print_it : public std::unary_function<int, int>
{
int
operator() (int i)
{
std::cout << i << " ";
return i;
}
};

int
main(int argc, char* argv[])
{
using namespace std;

vector<int*> foo;

cout << "foo [ ";
for(int i = 0; i < 10; i++)
{
int* kittens = new int(rand() % 32);
cout << *kittens << " ";
foo.push_back(kittens);
}
cout << "]" << endl;

cout << "foo [ ";
for_each( foo.begin(), foo.end(),
deref::unary_function<print_it>(print_it()) );
cout << "]" << endl;

exit(0);
}

=======================================

The two deref::create(...) functions in deref.cpp don't do what I would
like, however. When I try this call

for_each( foo.begin(), foo.end(),
deref::create(print_it()) );

for the for_each statement i get the error that goes

no match for call to `(unary_function<int, int>) (int &)'

which i guess is because my print_it object gets cast to
std::unary_function when it enters my create function, and then the
deref::unary_function object is instantiated with a std::unary_function
object and not a print_it object! Is there a way to rewrite
deref::create

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< what_so_ever_f_is >(f);
}

so that it puts the right type in where I need it?
 
T

Tobias Blomkvist

jsnX sade:
The two deref::create(...) functions in deref.cpp don't do what I would
like, however. When I try this call

for_each( foo.begin(), foo.end(),
deref::create(print_it()) );

for the for_each statement i get the error that goes

no match for call to `(unary_function<int, int>) (int &)'

which i guess is because my print_it object gets cast to
std::unary_function when it enters my create function, and then the
deref::unary_function object is instantiated with a std::unary_function
object and not a print_it object! Is there a way to rewrite
deref::create

template<typename Arg, typename Res>
unary_function< std::unary_function<Arg, Res> >
create(const std::unary_function<Arg, Res>& f)
{
return unary_function< what_so_ever_f_is >(f);
}

so that it puts the right type in where I need it?
Here's one solution, but it will only work if the function
object is derived from either virtual_binary_function
or unary_virtual_function

template<typename A1,typename A2, typename R>
class virtual_binary_function : public std::binary_function<A1,A2,R>
{
public:
virtual R operator()(A1,A2) = 0;
};

template<typename A, typename R>
class virtual_unary_function : public std::unary_function<A,R>
{
public:
virtual R operator()(A) = 0;
};

template<class F>
class unary_function
: public std::unary_function< typename F::argument_type*,
typename F::result_type >
{
public:

unary_function(const F& f) : f(f)
{}

typename F::result_type
operator() (typename F::argument_type* a)
{
return f(*a);
}

private:
const F & f; // <-!! Notice const and reference
};

struct print_it : public virtual_unary_function<int, int>
{
int operator() (int i)
{
std::cout << i << " ";
return i;
}
};

template<typename A, typename B>
unary_function< virtual_unary_function<A,B> >
create(const virtual_unary_function<A,B>& uf)
{
return unary_function< virtual_unary_function<A,B> >(uf);
}

template<typename A, typename B, typename C>
binary_function< virtual_binary_function<A,B,C> >
create(const virtual_binary_function<A,B,C>& uf)
{
return binary_function< virtual_binary_function<A,B,C> >(uf);
}

for_each( foo.begin(),foo.end(),create(print_it()) );

Tobias
 

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,774
Messages
2,569,598
Members
45,147
Latest member
CarenSchni
Top