C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

STL usage/style question

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
bigfaceworm
Guest





PostPosted: Wed Aug 04, 2004 12:13 pm    Post subject: STL usage/style question Reply with quote



I've got a data structure, a query tree.
It's got an interface:

QT::regionQuery(const Rectangle &, std::list<Obj> &results);

I want to change things so that you can specify whatever container
you want. And further, I want allow the user to pass in a function
that gets called on each one (instead of adding the objects to a container).

Now, looking at STL docs, it looks like there are two different ways
I could do one of a couple of things:

1) use a UnaryFunction, the example being for_each

http://www.sgi.com/tech/stl/for_each.html

2) use an insert_iterator

http://www.sgi.com/tech/stl/insert_iterator.html

The style question I have is that I'd like to provide one entry point

QT::regionQuery(const Rectangle&, BLAHTYPE &);

Where BLAHTYPE maps easily to both types of use, adding to a container,
and calling a function.

My problem is that a UnaryFunction has an operator()(Type)
where insert_iterator uses operator*() and operator=()

So if BLAHTYPE is functor-like, then everyone wanting to use a contiainer
has to do some non-STL type manipulation. And the same argument goes for
BLAHTYPE being modeled after an insert_iterator.

What's the solution to my dilemna?

thanks.

BFW

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Maxim Yegorushkin
Guest





PostPosted: Thu Aug 05, 2004 10:43 am    Post subject: Re: STL usage/style question Reply with quote



bigfaceworm <bigfaceworm (AT) hotmail (DOT) com> wrote:

Quote:
It's got an interface:

QT::regionQuery(const Rectangle &, std::list<Obj> &results);

I want to change things so that you can specify whatever container
you want. And further, I want allow the user to pass in a function
that gets called on each one (instead of adding the objects to a container).

[]


Quote:
My problem is that a UnaryFunction has an operator()(Type)
where insert_iterator uses operator*() and operator=()

[]

Quote:
What's the solution to my dilemna?

SFINAE might be a solution. Well, the code is worth 0x100 words:

// the wrapper is needed to correctly handle reference types,
// because if value_type or result_type happens to be a reference
// the expression value_type* is ill-formed
template<class T>
struct wrap;

// selected only when Iterator has value_type typedef
template<class Iterator>
void f(Iterator i, wrap<typename Iterator::value_type>* = 0)
{
std::cout << "iteratorn";
}

// selected only when Functor has result_type typedef
template void f(Functor f, wrap<typename Functor::result_type>* = 0)
{
std::cout << "functorn";
}

int main()
{
f(std::less f(std::reverse_iterator<int*>());
}

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
bigfaceworm
Guest





PostPosted: Fri Aug 06, 2004 10:29 am    Post subject: Re: STL usage/style question Reply with quote



"Maxim Yegorushkin" <e-maxim (AT) yandex (DOT) ru> wrote

Quote:
SFINAE might be a solution. Well, the code is worth 0x100 words:

Thanks for the code snippet. It was a nice solution to determining
whether the object is a stl::function or a stl::iterator.

My end goal is to have 1 function 'f' that does the work.
So, I wrote a little converter that takes an iterator and
creates a wrapper function such that I only have to implement
to one interface.

I've attached that code in case anyone would like to give me feedback
(it would be appreciated).

My follow-up questions are:

Is it possible to provide a wrapper for an ostream_iterator?
How is it done?

The difficulty I have is that to create a std::unary_function<>
I need to know the argument type (duh).

Well, I cannot seem to get the argument type of a std::ostream_iterator

std::ostream_iterator::value_type is void
And none of the other typedefs provided seem to help.

thanks for any suggestions,

BFW


-------------------------------------------------------------------------
// the wrapper is needed to correctly handle reference types,
// because if value_type or result_type happens to be a reference
// the expression value_type* is ill-formed
template<class T>
struct wrap;

// turn an iterator into a functor
template<class Iterator, class T>
struct iterator_wrapper : public std::unary_function<T, Iterator>
{
Iterator i_;
iterator_wrapper(Iterator i) : i_(i) {};
Iterator operator()(T &x) { *i_ = x; return ++i_; }
};

// selected only when Iterator has container_type typedef
template<class Iterator>
void f(Iterator i, wrap<typename Iterator::container_type>* = 0)
{
std::cout << "container iterator -> functorn";

f(iterator_wrapper<Iterator, typename Iterator::container_type::value_type>(i));
}

// selected only when Functor has result_type typedef
template<class Functor>
void f(Functor fn, wrap<typename Functor::result_type>* = 0)
{
std::cout << "functorn";

// do something
std::vector std::for_each(v.begin(), v.end(), fn);
}

struct printer : public std::unary_function<int, void>
{
printer() {}
void operator()(int x) { std::cout << x << " "; }
};

int main()
{
std::vector f(std::inserter(v, v.end()));

std::cout << "v now has " << v.size() << " elements " << std::endl;
f(printer());
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
James Hopkin
Guest





PostPosted: Fri Aug 06, 2004 2:45 pm    Post subject: Re: STL usage/style question Reply with quote

"Maxim Yegorushkin" <e-maxim (AT) yandex (DOT) ru> wrote

Quote:
// selected only when Iterator has value_type typedef
template<class Iterator
void f(Iterator i, wrap {
std::cout << "iteratorn";
}

// selected only when Functor has result_type typedef
template void f(Functor f, wrap {
std::cout << "functorn";
}


Quite cute, but beware of using 'name conformance' in this way. Not
everything which has a nested type called 'value_type' is an iterator.
Accidentally passing in a container could lead to nasty surprises.
You'd get highly cryptic error messages at the very least.

My personal opinion is that you should provide for the most common
case (either output iterator or functor), possibly providing a helper
class for the other case. The output iterator option gives the client
the choice of either using a custom iterator or (more transparently)
filling up a container and calling for_each on that.

You could of course have two differently named functions. This would
be the most STL-like solution: for_each_object_in_region(...) and
transform_objects_in_region(...)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maxim Yegorushkin
Guest





PostPosted: Fri Aug 06, 2004 2:50 pm    Post subject: Re: STL usage/style question Reply with quote

bigfaceworm <bigfaceworm (AT) hotmail (DOT) com> wrote:

[]

Quote:
Is it possible to provide a wrapper for an ostream_iterator?
How is it done?

The difficulty I have is that to create a std::unary_function
I need to know the argument type (duh).

Well, I cannot seem to get the argument type of a std::ostream_iterator

Why do you need to derive std::unary_function<>? More specifically, why
do you need the argument_type typedefs?

AFAIK, the argument_type typedefs that std::unary_function<> /
std::binary_function<> define only used by std::binder1st/2nd,
std::unary/binary_negate and extension std::compose. If you don't need
support for those, you can drop derivation from std::*ary_function<> and
just define result_type typedef in your wrapper. Note, that boost::bind
offers the functionality of those functors and even more and does not
requre the argument_type typedefs (I am not sure about negate, but I
remember being told that boost::bind would support ! for negating the result).

Quote:
// selected only when Iterator has container_type typedef
template<class Iterator
void f(Iterator i, wrap {
std::cout << "container iterator -> functorn";

f(iterator_wrapper<Iterator, typename Iterator::container_type::value_type>(i));
}

You also might want to add f() overload for plain pointers because a
plain pointer is also an iterator.

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maxim Yegorushkin
Guest





PostPosted: Sat Aug 07, 2004 3:27 am    Post subject: Re: STL usage/style question Reply with quote

James Hopkin <jhopkin (AT) reflectionsinteractive (DOT) com> wrote:

Quote:
"Maxim Yegorushkin" <e-maxim (AT) yandex (DOT) ru> wrote

// selected only when Iterator has value_type typedef
template<class Iterator
void f(Iterator i, wrap {
std::cout << "iteratorn";
}

// selected only when Functor has result_type typedef
template void f(Functor f, wrap {
std::cout << "functorn";
}


Quite cute, but beware of using 'name conformance' in this way. Not
everything which has a nested type called 'value_type' is an iterator.
Accidentally passing in a container could lead to nasty surprises.
You'd get highly cryptic error messages at the very least.

That's true. To be more specific, one may use iterator_category nested
typedef instead of value_type (the latter was the first thing that came
to my mind). And provide an overload for plain pointers as they are
iterators too.

[]

Quote:
You could of course have two differently named functions. This would
be the most STL-like solution: for_each_object_in_region(...) and
transform_objects_in_region(...)

That is a good clear approach that also puts probably less strain on the
compiler. But, I think, it's not that much fun as with SFINAE :)

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
bigfaceworm
Guest





PostPosted: Sat Aug 07, 2004 9:27 am    Post subject: Re: STL usage/style question Reply with quote

"Maxim Yegorushkin" <e-maxim (AT) yandex (DOT) ru> wrote

Quote:
AFAIK, the argument_type typedefs that std::unary_function<> /
std::binary_function<> define only used by std::binder1st/2nd,
std::unary/binary_negate and extension std::compose. If you don't need
support for those, you can drop derivation from std::*ary_function<> and
just define result_type typedef in your wrapper. Note, that boost::bind
offers the functionality of those functors and even more and does not
requre the argument_type typedefs (I am not sure about negate, but I
remember being told that boost::bind would support ! for negating the result).

Fair enough. I guess I was looking for an automated way to distinguish between
the various types. And my solution wouldn't have fit boost::bind w/out yet
another specialization.

My only concern was trying to minimize overhead - this structure is at the
core of the project and can't be slow - so the common case (insert_iterator)
has to be as fast as the hard-coded list<> is right now (yes, list is slower
than array for plain inserts, but I can't go slower).

And I'm inexperienced in the temlplate world and figure that I'm going to do
something that works functionally but possibly takes X times as long to compile
as it'll need to and Y times as long to run...

[]
Quote:
You also might want to add f() overload for plain pointers because a
plain pointer is also an iterator.

True. Thanks.


BFW

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
bigfaceworm
Guest





PostPosted: Sat Aug 07, 2004 9:27 am    Post subject: Re: STL usage/style question Reply with quote

[email]jhopkin (AT) reflectionsinteractive (DOT) com[/email] (James Hopkin) wrote in message news:<a0368c9c.0408060113.761fb0fe (AT) posting (DOT) google.com>...
Quote:
Quite cute, but beware of using 'name conformance' in this way. Not
everything which has a nested type called 'value_type' is an iterator.
Accidentally passing in a container could lead to nasty surprises.
You'd get highly cryptic error messages at the very least.

True, and as I found out, not all STL iteratorshave the 'value_type'
- as in the ostream_iterator.

Why is that?

Quote:

My personal opinion is that you should provide for the most common
case (either output iterator or functor), possibly providing a helper
class for the other case. The output iterator option gives the client
the choice of either using a custom iterator or (more transparently)
filling up a container and calling for_each on that.

In my case, the output iterator is the most common case right now,
but this is only because we always get a list of objects and then
iterate... I'm trying to get people to think more functionally.

Quote:
You could of course have two differently named functions. This would
be the most STL-like solution: for_each_object_in_region(...) and
transform_objects_in_region(...)

The only problem with this is that the iterator/functor is used/passed around
to 10-12 routines, which is a lot of code duplication. And that's what I'm
trying to avoid.

I'll just provide helper functions for people wishing to pass in a function.


Thanks,

BFW

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Carl Barron
Guest





PostPosted: Sun Aug 08, 2004 10:08 am    Post subject: Re: STL usage/style question Reply with quote

In article <2bd747c7.0408061821.2d5e25de (AT) posting (DOT) google.com>,
bigfaceworm <bigfaceworm (AT) hotmail (DOT) com> wrote:

Quote:
My only concern was trying to minimize overhead - this structure is at the
core of the project and can't be slow - so the common case (insert_iterator)
has to be as fast as the hard-coded list<> is right now (yes, list is slower
than array for plain inserts, but I can't go slower).

I guess you want
template <class Out>
QT::some_query(Rectangle &r,Out out)
{
/* apply some query involving r and members of a member container
writing the results found to an iterator Out if they match the
query
*/
}

If this is correct then

std::list<Item> results;
Rectangle r;
some_qt.some_query(r,std::back_inserter(results));

copies the results to a list in the order found.


some_qt.some_query(r,std::ostream_iterator<Item>(some_stream," "));
writes to some_stream via operator << (std::ostream &,const Item &);


struct foo
{
std::list explicit foo(std::list<Item> &a):where(a){}
void operator () (const Item & x)
{
where.push_back(x.some_func());
}
}:

std::list<Item> results;
foo f(results);
some_qt:some_query(r,make_function_output_iterator(f)):
applies some_func() to each matching item an placing them on results
atter the application of some_func().

I would guess that there is little to gain by hand optimizing at this
stage is dangerous.

see boost/function_output_iterator.hpp for an output iterator that
preferms a function on each operator *ot = x.

www.boost.org is a link to boost....

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
bigfaceworm
Guest





PostPosted: Sat Aug 21, 2004 4:07 am    Post subject: Re: STL usage/style question Reply with quote

Carl Barron <cbarron413 (AT) adelphia (DOT) net> wrote

Quote:
see boost/function_output_iterator.hpp for an output iterator that
preferms a function on each operator *ot = x.

Thanks. I just wrote one. Now I can compare to see what I did
wrong/suboptimally. ;-)


BFW

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.