function object for [] and *

R

Rares Vernica

Hello,

I need help to replace the following code:

int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];

with something like:

int *idx; //...
std::transform(idx, idx + n, out, ...);

I think the operator for transform should look something like:

__gnu_cxx::compose1(in[], *idx)

So, I think, I need a function object to apply the [] operator to "in",
given an int and another one to apply the * operator to each element in
"idx".

Thanks in advance,
Rares Vernica
 
A

AnonMail2005

Hello,

I need help to replace the following code:

  int *idx; //...
  for (int i = 0; i < n; i++, ++out)
    out = in[idx];

with something like:

  int *idx; //...    
  std::transform(idx, idx + n, out, ...);

I think the operator for transform should look something like:

    __gnu_cxx::compose1(in[], *idx)

So, I think, I need a function object to apply the [] operator to "in",
given an int and another one to apply the * operator to each element in
"idx".

Here's a first cut assuming the contents of in and out are doubles.
If they're not, change accordingly...

struct Functor
{
std::vector<double> const & m_in;

// constructor
Functor (std::vector<double> const & in) : m_in (in)
{}

// functor operator
double operator () (int i) const
{
return in ;
}
}

std::transform (idx, idx + n, out, Functor (in));

Make sure out has enough room in out or use std::back_inserter (out).

HTH
 
N

Noah Roberts

Hello,

I need help to replace the following code:

int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];

with something like:

int *idx; //...
std::transform(idx, idx + n, out, ...);

I think the operator for transform should look something like:

__gnu_cxx::compose1(in[], *idx)

So, I think, I need a function object to apply the [] operator to "in",
given an int and another one to apply the * operator to each element in
"idx".

Here's a first cut assuming the contents of in and out are doubles.
If they're not, change accordingly...

struct Functor
{
std::vector<double> const & m_in;

// constructor
Functor (std::vector<double> const & in) : m_in (in)
{}

// functor operator
double operator () (int i) const
{
return in ;
}
}

std::transform (idx, idx + n, out, Functor (in));

Make sure out has enough room in out or use std::back_inserter (out).

HTH


You might also try something like so (untested):

std::transform(idx, idx+n, out, boost::bind(&in_type::eek:perator[], in, _1));
 
E

Eric Pruneau

Rares Vernica said:
Hello,

I need help to replace the following code:

int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];

with something like:

int *idx; //...
std::transform(idx, idx + n, out, ...);

I think the operator for transform should look something like:

__gnu_cxx::compose1(in[], *idx)

So, I think, I need a function object to apply the [] operator to "in",
given an int and another one to apply the * operator to each element in
"idx".

Thanks in advance,
Rares Vernica



here is a generic way to do what you want using only stl stuff.

using namespace std;

// here is the functor, I assume idx is always of type int, if not, replace
it with a template parameter

template<typename T_out, typename T_in>
struct Get : public binary_function<int, T_in, T_out>
{
// binary_function is needed by bind2nd
T_out operator()(int idx, T_in in) const
{
return in[idx];
}
};

int main()
{
int idx[3] = {0,1,2};
int in[3] = {5,4,3};
int out[3];

transform(idx, idx+3, out, bind2nd(Get<int,int*>(), &in[0]));

cout << out[0] <<"\n" <<out[1] <<"\n" <<out[2] <<"\n";
return 0;
}

this print:
5
4
3
 
N

Noah Roberts

Eric said:
Rares Vernica said:
Hello,

I need help to replace the following code:

int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];

with something like:

int *idx; //...
std::transform(idx, idx + n, out, ...);

I think the operator for transform should look something like:

__gnu_cxx::compose1(in[], *idx)

So, I think, I need a function object to apply the [] operator to "in",
given an int and another one to apply the * operator to each element in
"idx".

Thanks in advance,
Rares Vernica



here is a generic way to do what you want using only stl stuff.


That is good, but it should be kept in mind that boost's bind will be in
the next standard library as part of the "stl". Unless you're being
told not to use it I would definitely recommend getting it and learning
how. It's power and simplicity (as long as you're not trying to read
it) is not even remotely reached by the current library's binders.
 
J

James Kanze

I need help to replace the following code:
int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];

with something like:
int *idx; //...
std::transform(idx, idx + n, out, ...);

Why? The first is simple and easily readable. The second is
likely to be obfuscation, unless you can find a very good name
for the functional object. Unless this is a "standard"
transformation, occuring in many different places in your
application, you're almost certainly better off sticking with
the orginal loop.

At least for now. I believe that the next version of the
standard will have some sort of support for lambdas; using
transform with a lambda function here would make a lot of sense.
Moving the transformation itself out into a separate object
doesn't, however, unless that object is generally usable and can
be given a good name which reflects what it does. And trying to
simulate lambda with variations of boost::bind is probably not
going to result in anything readable.
I think the operator for transform should look something like:
__gnu_cxx::compose1(in[], *idx)

In other words, it should be some obscure object that many C++
programmers aren't familiar with, rather than straightforward
code which anyone can understand.
 
J

James Kanze

I need help to replace the following code:
int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];
with something like:
int *idx; //...
std::transform(idx, idx + n, out, ...);
I think the operator for transform should look something like:
__gnu_cxx::compose1(in[], *idx)
So, I think, I need a function object to apply the []
operator to "in", given an int and another one to apply the
* operator to each element in "idx".

Here's a first cut assuming the contents of in and out are
doubles. If they're not, change accordingly...
struct Functor
{
std::vector<double> const & m_in;
// constructor
Functor (std::vector<double> const & in) : m_in (in)
{}
// functor operator
double operator () (int i) const
{
return in ;
}
}
std::transform (idx, idx + n, out, Functor (in));
Make sure out has enough room in out or use std::back_inserter (out).

You might also try something like so (untested):
std::transform(idx, idx+n, out, boost::bind(&in_type::eek:perator[], in, _1));

Which won't work if in_type is a C style array (or a pointer).
(Otherwise, a simple, direct application of boost::bind is still
readable enough that I would consider it more or less
acceptable. Although I don't see anything wrong with the
original code, and I'd probably wait until we get lambda
expressions to upgrade it.)
 
J

James Kanze

Eric said:
Rares Vernica said:
I need help to replace the following code:
int *idx; //...
for (int i = 0; i < n; i++, ++out)
out = in[idx];
with something like:
int *idx; //...
std::transform(idx, idx + n, out, ...);
I think the operator for transform should look something like:
__gnu_cxx::compose1(in[], *idx)
So, I think, I need a function object to apply the []
operator to "in", given an int and another one to apply the
* operator to each element in "idx".

here is a generic way to do what you want using only stl stuff.

That is good,

Actually, it's mostly good for obfuscation, moving the
transformation logic out of the function, and forcing the reader
to look elsewhere to know what is going on.
but it should be kept in mind that boost's bind will be in the
next standard library as part of the "stl". Unless you're
being told not to use it I would definitely recommend getting
it and learning how. It's power and simplicity (as long as
you're not trying to read it) is not even remotely reached by
the current library's binders.

Boost's bind definitely belongs in everyone's tool kit, but it
has it's limits as well---if the operator[] in question is the
built in version, for example, it won't work. The next version
of the standard will also include some support for lambda
expressions, which would be an even more general solution.
 
G

gpderetta

Eric said:
"Rares Vernica" <[email protected]> a écrit dans le message de (e-mail address removed)...
I need help to replace the following code:
 int *idx; //...
 for (int i = 0; i < n; i++, ++out)
   out = in[idx];
with something like:
 int *idx; //...
 std::transform(idx, idx + n, out, ...);
I think the operator for transform should look something like:
   __gnu_cxx::compose1(in[], *idx)
So, I think, I need a function object to apply the []
operator to "in", given an int and another one to apply the
* operator to each element in "idx".
here is a generic way to do what you want using only stl stuff.

That is good,


Actually, it's mostly good for obfuscation, moving the
transformation logic out of the function, and forcing the reader
to look elsewhere to know what is going on.
but it should be kept in mind that boost's bind will be in the
next standard library as part of the "stl".  Unless you're
being told not to use it I would definitely recommend getting
it and learning how.  It's power and simplicity (as long as
you're not trying to read it) is not even remotely reached by
the current library's binders.

Boost's bind definitely belongs in everyone's tool kit, but it
has it's limits as well---if the operator[] in question is the
built in version, for example, it won't work.  The next version
of the standard will also include some support for lambda
expressions, which would be an even more general solution.


It will also not work if operator[] has been overloaded for const and
non const 'this' (as it is usually the case). You need an explicit
(and ugly) cast then. The OP bind example also has a problem if used
with any container but plain arrays: bind closes its arguments by copy
so it will cause the container to be copied: use boost::ref or
boost::cref.

With boost lambda you can do:

namespace ll = boost::lambda;
std::transform(idx, idx+n, out, ll::ret<whatever>(ll::var(in)[_1]));

where 'whatever' is the result type for operator[]. In this case the
const qualified value_type of 'in' should be enough. For std::vector
(and standard containers in general) and builtin arrays, you do not
need 'ret<>':

namespace ll= boost::lambda;

std::vector<int> m = ...;
std::vector<int> idx = ...;
std::vector<int> out = ...;
std::transform(idx.begin(), idx.end(), out.begin(), ll::var(m)
[ll::_1]);

Which doesn't look that ugly.
 
J

James Kanze

On Jun 25, 9:46 am, James Kanze <[email protected]> wrote:

[...]
Boost's bind definitely belongs in everyone's tool kit, but it
has it's limits as well---if the operator[] in question is the
built in version, for example, it won't work. The next version
of the standard will also include some support for lambda
expressions, which would be an even more general solution.
It will also not work if operator[] has been overloaded for const and
non const 'this' (as it is usually the case). You need an explicit
(and ugly) cast then.

Good point.
The OP bind example also has a problem if used
with any container but plain arrays: bind closes its arguments by copy
so it will cause the container to be copied: use boost::ref or
boost::cref.
With boost lambda you can do:
namespace ll = boost::lambda;
std::transform(idx, idx+n, out, ll::ret<whatever>(ll::var(in)[_1]));
where 'whatever' is the result type for operator[]. In this case the
const qualified value_type of 'in' should be enough. For std::vector
(and standard containers in general) and builtin arrays, you do not
need 'ret<>':
namespace ll= boost::lambda;

std::vector<int> m = ...;
std::vector<int> idx = ...;
std::vector<int> out = ...;
std::transform(idx.begin(), idx.end(), out.begin(), ll::var(m)
[ll::_1]);
Which doesn't look that ugly.

No. I didn't consider boost::lambda, because it seems that
every time I try it on something real, I hit up against some
limitations of it, and end up having to add extra qualifiers,
etc., in order to make it work. Of course, your ll::var would
qualify there, but in this case, I guess the rest of the
expression is simple enough that it doesn't feel too bothersome.

In general, I think real support for lambdas (at the language
level) should open up a lot of possibilities along these lines.
 

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,776
Messages
2,569,603
Members
45,190
Latest member
ClayE7480

Latest Threads

Top