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 

I'd like to use STL algorithms
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
imbunche
Guest





PostPosted: Tue Sep 19, 2006 10:20 pm    Post subject: I'd like to use STL algorithms Reply with quote



Hi,

The following code applys a conversion function to elements on a vector
depending on its index, as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);
// or ... val.push_back(convert(i,v[i]));
}

The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
.....

Please help,
thx in advance.


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





PostPosted: Wed Sep 20, 2006 8:29 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote



imbunche wrote:
Quote:
Hi,

The following code applys a conversion function to elements on a vector
depending on its index, as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);
// or ... val.push_back(convert(i,v[i]));
}

The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
....

I think that std::accumulate could be used to solve this problem. For
example, I would first declare a function (or a function object) that
accepts an index value and a reference to a "sometype" type as
parameters, and which returns the accumulated value (serving as the
index) incremented by one:

int AccumulateProc(int acc, sometype& t)
{
t = convert(acc, t);
return acc+1;
}

And then pass this routine (or object) to std::accumlate like so:

#include <vector>
#include <numeric>
...

std::vector<sometype> v;
...

int acc;

acc = accumulate( v.begin(), v.end(), 0, AccumulateProc);

The sometype elements in the vector will have been converted in place.
Note that for this code to compile, sometype must be assignable (that
is, it may be necessary implement operator=() for sometype's).

Greg


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





PostPosted: Wed Sep 20, 2006 8:40 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote



imbunche wrote:
Quote:
The following code applys a conversion function to elements on a vector
depending on its index,
^^^^^^^^^^^^^^^^^^^^^^^ this is the problem!


Quote:
as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);
// or ... val.push_back(convert(i,v[i]));
}

The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
....

The point is that this is not a single conversion but many different
ones, because they depend on the position of the element inside the vector.
Sorry, but I think that the algorithms of the stdlibrary are simply not
the right tool here. I also couldn't think of a way to express it
stdlibrary-like, as it typically deals with sequences that are mostly
not even accessible via an index.

Uli


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





PostPosted: Wed Sep 20, 2006 8:44 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

imbunche wrote:
Quote:
Hi,

The following code applys a conversion function to elements on a vector
depending on its index, as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);

don't you mean val[i] = convert(i, tokens[i]); ?

Quote:
// or ... val.push_back(convert(i,v[i]));
}

The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
....
if you make convert an object it can hold the index

struct convert
{
convert() : index(0){}

sometype operator()(tokens::value_type&)
{
use index and increment it at the end
}

size_t index;
};

extend from unary_function, you don't need bind


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






PostPosted: Wed Sep 20, 2006 9:33 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

imbunche wrote:
Quote:
The following code applys a conversion function to elements of a vector
depending on its index, as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);
// or ... val.push_back(convert(i,v[i]));
}

I assume you mean tokens[i] instead of v[i]? You really should include
declarations.

You rely on an indexed container here; it wouldn't work if you just
had an iterator range [begin, end) .

Quote:
The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));

Here you're working with iterators, which is quite typical for STL.
The closest thing you have to an iterator is std::distance(begin, _1)
but that isn't really an index.

HTH,
Michiel


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





PostPosted: Wed Sep 20, 2006 9:35 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

Quote:
The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
....

What about wrapping your convert into a functor that can increment a
member var for a counter everytime its called? Something like (I know
this won't compile and it's not optimal, it's just to give you the
idea):

This convert functor simply increments the value passed in and returns
a std::pair of the index and incremented value


template<typename T>
struct convert : public std::unaryfunctor<std::pair<int, T>, T>
{
public:
convert() : count(0){}

std::pair<int, T> operator()(T item) {
return std::make_pair(this->count++, ++item);
}
private:
int count;
};

You could then call transform like this:

transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
convert<T>());


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





PostPosted: Thu Sep 21, 2006 10:10 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

Greg Herlihy wrote:
Quote:
imbunche wrote:

The following code applys a conversion function to elements
on a vector depending on its index, as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);
// or ... val.push_back(convert(i,v[i]));
}

The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
....

I think that std::accumulate could be used to solve this
problem.

His problem modifies every element in an array. std::accumulate
in non-mutating with regards to the sequence it receives. You
could probably come up with some sort of accumulator type or
operator which contains a reference to the vector, and modifies
it, but that's more obfuscation than anything else.

His iteration actually involves the numerical value of the
index. As such, any conversion to the STL is likely to be
obfuscation, or at least more work, requiring that he maintain
the index manually anyway. In general, when the numerical value
of the index is significant, the STL (nor any other library
based on iterators) is not the answer.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


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





PostPosted: Thu Sep 21, 2006 10:15 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

Vladimir Marko wrote:
Quote:
imbunche wrote:

The following code applys a conversion function to elements
on a vector depending on its index, as follows:

int i;
vector<sometype> val;
for (i=0; i<tokens.size(); ++i)
{
val[i] = convert(i,v[i]);
// or ... val.push_back(convert(i,v[i]));
}

The best I have achieved (with my limited STL knowledge is:
transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
bind (convert,
0, _1));
Which is useless of course becauss it fixes the first parameter of
convert to 0, ... I need some kind of i++ but I cannot find the way
....

You need the boost::counting_iterator and the second overload
of transform:
std::transform(
tokens.begin(),tokens.end(), // first1, last1
boost::counting_iterator<std::size_t>(0u), // first2
tokens.begin(), // result
boost::bind(convert,_2,_1) // binary_op
//< in which namespace are _1 and _2? Never mind.
);
See http://www.boost.org/libs/iterator/doc/counting_iterator.html .

Clever but... doesn't this sort of hide the fact that the
transformation done to each element is a function of the
numeric value of its index in the array? And as such, count as
obfuscation?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


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





PostPosted: Thu Sep 21, 2006 11:17 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

Dan McLeran ha scritto:
Quote:

template<typename T
struct convert : public std::unaryfunctor<std::pair<int, T>, T
{
public:
convert() : count(0){}

std::pair<int, T> operator()(T item) {
return std::make_pair(this->count++, ++item);
}
private:
int count;
};

You could then call transform like this:

transform(tokens.begin(), tokens.end(),
back_inserter(val), // where to put results.
convert<T>());


This approach calls for undefined behavior in the current C++ standard,
because binary_op is not allow to cause any side effects (in this case,
incrementing count is a side effect).

However, I just checked on comp.std.c++ that the situation is going to
be a bit different with the next C++ revision as this case will be
"demoted" from undefined to unspecified behavior. It's unspecified
because of two facts:

1) std::transform can make any number of copies of the binary_op and
that might interfere with keeping the count

2) the standard does not guarantee that the elements are processed in
order from the first to the last, so the count might mismatch the
traversed elements

The idea is that binary_op should be, as the name suggests, a binary
operator whose output depends uniquely from its input and not from any
stored state.

Ganesh

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





PostPosted: Fri Sep 22, 2006 1:03 am    Post subject: Re: I'd like to use STL algorithms Reply with quote

Quote:
This approach calls for undefined behavior in the current C++ standard,
because binary_op is not allow to cause any side effects (in this case,
incrementing count is a side effect).

I didn't use a binary functor, I used a unary functor. I also don't
agree that incrementing an internal counter of a function object is a
side effect of calling transform with a unary functor.


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





PostPosted: Fri Sep 22, 2006 5:10 am    Post subject: Re: I'd like to use STL algorithms Reply with quote

Dan McLeran ha scritto:
Quote:
This approach calls for undefined behavior in the current C++ standard,
because binary_op is not allow to cause any side effects (in this case,
incrementing count is a side effect).

I didn't use a binary functor, I used a unary functor. I also don't
agree that incrementing an internal counter of a function object is a
side effect of calling transform with a unary functor.

Sorry, I incorrectly wrote binary_op but the same argument applies to a
unary op (see 25.2.3/2). About what constitutes a side-effect, my
statement is based on the definition given in 1.9/7 (emphasis added):

1.9/7: Accessing an object designated by a volatile lvalue (3.10),
*modifying an object*, calling a library I/O function, or calling a
function that does any of those operations are all side effects, which
are changes in the state of the execution environment.

Incrementing a counters is a modification of an object (the counter
itself) so it is a side effect according to this definition.

Anyway, even if we assume the relaxed wording of the draft (which
doesn't mention the term "side effect"), the code you posted is not
guaranteed to work as you expect.

Ganesh

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





PostPosted: Fri Sep 22, 2006 5:18 am    Post subject: Re: I'd like to use STL algorithms Reply with quote

kanze wrote:
Quote:
Vladimir Marko wrote:
You need the boost::counting_iterator and the second overload
of transform:
std::transform(
tokens.begin(),tokens.end(), // first1, last1
boost::counting_iterator<std::size_t>(0u), // first2
tokens.begin(), // result
boost::bind(convert,_2,_1) // binary_op
//< in which namespace are _1 and _2? Never mind.
);
See http://www.boost.org/libs/iterator/doc/counting_iterator.html .

Clever but... doesn't this sort of hide the fact that the
transformation done to each element is a function of the
numeric value of its index in the array? And as such, count as
obfuscation?

Doesn't "counting_iterator" say that I'm actually counting something?
This doesn't seem obfuscated to me. Then again, there are many things
that seem pretty obvious to me and hard to understand to others or
vice versa.

Cheers,
Vladimir Marko


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





PostPosted: Fri Sep 22, 2006 5:39 am    Post subject: Re: I'd like to use STL algorithms Reply with quote

kanze ha scritto:
Quote:

His iteration actually involves the numerical value of the
index. As such, any conversion to the STL is likely to be
obfuscation, or at least more work, requiring that he maintain
the index manually anyway. In general, when the numerical value
of the index is significant, the STL (nor any other library
based on iterators) is not the answer.


I believe it should be easy to implement an iterator adapter that
produces pairs (index, it). Basically it might be similar to
boost::counting_iterator holding two incrementables instead of one.
Then you could use something like:

std::transform(
make_double_counting_iterator(tokens.begin(), 0), // 0 is start index
make_double_counting_iterator(tokens.end(), -1), // -1 is a dummy
back_inserter(val),
convert_adapter());

where convert_adapter is

struct convert_adapter
{
template <class It, class Diff>
void convert(const std::pair<It, Diff>& p)
{ convert(p.second, *p.first); }
};

Apart from the necessity of the adapter, I don't see this code so
obfuscated. How would you rate this design? double_counting_iterator is
not tied to this problem domain and could also be useful as a generic tool.

Ganesh

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





PostPosted: Fri Sep 22, 2006 5:45 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

Vladimir Marko wrote:
Quote:
kanze wrote:
Vladimir Marko wrote:
You need the boost::counting_iterator and the second overload
of transform:
std::transform(
tokens.begin(),tokens.end(), // first1, last1
boost::counting_iterator<std::size_t>(0u), // first2
tokens.begin(), // result
boost::bind(convert,_2,_1) // binary_op
//< in which namespace are _1 and _2? Never mind.
);
See http://www.boost.org/libs/iterator/doc/counting_iterator.html .

Clever but... doesn't this sort of hide the fact that the
transformation done to each element is a function of the
numeric value of its index in the array? And as such, count as
obfuscation?

Doesn't "counting_iterator" say that I'm actually counting something?
This doesn't seem obfuscated to me. Then again, there are many things
that seem pretty obvious to me and hard to understand to others or
vice versa.

Well, it certainly depends on the point of view. If the idea is
a function dependant on the index, I find it a lot clearer to
use the index. If the idea is a function depending on how many
times it has been invoked, then the counting_iterator is
clearer. My point is just that your solution obscures the
relationship between the function and the index; the
counting_iterator duplicates the behavior of the iterator into
the container, in order to recreate the index behind it, but the
relationship is indirect enough to not be immediately clear.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


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





PostPosted: Fri Sep 22, 2006 5:46 pm    Post subject: Re: I'd like to use STL algorithms Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
kanze ha scritto:

His iteration actually involves the numerical value of the
index. As such, any conversion to the STL is likely to be
obfuscation, or at least more work, requiring that he maintain
the index manually anyway. In general, when the numerical value
of the index is significant, the STL (nor any other library
based on iterators) is not the answer.

I believe it should be easy to implement an iterator adapter
that produces pairs (index, it). Basically it might be similar
to boost::counting_iterator holding two incrementables instead
of one. Then you could use something like:

std::transform(
make_double_counting_iterator(tokens.begin(), 0), // 0 is start index
make_double_counting_iterator(tokens.end(), -1), // -1 is a dummy
back_inserter(val),
convert_adapter());

where convert_adapter is

struct convert_adapter
{
template <class It, class Diff
void convert(const std::pair<It, Diff>& p)
{ convert(p.second, *p.first); }
};

Apart from the necessity of the adapter, I don't see this code
so obfuscated. How would you rate this design?
double_counting_iterator is not tied to this problem domain
and could also be useful as a generic tool.

There's one thing I'm having trouble understanding here: if the
problem is stated in terms of 'for index i, do convert(i)', why
do you want to get rid of the index? Any removal of the index
here is obfuscation; it hides the basic statement of the problem
we are trying to solve. Why do you want to add all the
complexity of a new type of iterator, and an adapter, for what
is basically a simple problem?

When the numeric value of the index is significant, any use of
iterators seems wrong to me. The whole idea behind an iterator,
as I see it, is to free the concept of visiting a sequence of
objects in succession from the need of a numeric value. If you
need the numeric value, you don't want an iterator, if you can
avoid it.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ 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
Goto page 1, 2  Next
Page 1 of 2

 
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.