Pregunta

I am trying to write a binary function that takes two vectors(of the same length) and adds them by value. For some reason the following code does not work:

struct Plusval : binary_function <std::vector<int>,std::vector<int>,std::vector<int> > 
{
  std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y) const
{
    std::vector<int> ret(x);
    std::vector<int>::iterator itx,ity;
    ity=y.begin();
    for (itx=ret.begin();itx<ret.end();++itx)
    {
        ret[*itx]+=y[*ity];
        ++ity;
    }
    return ret;
  }
};

I get an error that I can't do ity=y.begin() However, the following code does work

struct Plusval : binary_function <std::vector<int>,std::vector<int>,std::vector<int> > 
{
  std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y) const
{
    std::vector<int> ret(x);
    std::vector<int> yloc(y);
    std::vector<int>::iterator itx,ity;
    ity=yloc.begin();
    for (itx=ret.begin();itx<ret.end();++itx)
    {
        ret[*itx]+=yloc[*ity];
        ++ity;
    }
    return ret;
  }
};

Obviously, the second version will take longer (since it has to copy an additional vector). Is it because the input is a const vector? If it is, is there any reason it needs to be? Note that I am planning on using this function as an input to the allreduce() function in boost::mpi if that makes any difference

¿Fue útil?

Solución

You define ity as vector::iterator y is const and returns a const_iterator.

What is more important is: Don't use binary_function. The adapters have been deprecated.

Also, your function does not do what you want. *itx returns the value stored at the position pointed to by itx and you use it to index into the you intend to return vector.

I would write this with a binary transform.

std::vector<int> res;
std::transform(begin(x), end(x), begin(y), 
               std::back_inserter(res), std::plus<int>());

Otros consejos

The error is that you cannot use non-const iterators with a const container, as that would break const-correctness. You should use std::vector<int>::const_iterator on the second argument.

Other than that, the implementation in the first block does not do what you claim it does.You are iterating over the container and using the stored values to index into the container and update there. If you actually want to add the values from the two containers, it is much simpler than that:

struct PlusVal
{
   std::vector<int> operator()( std::vector<int> lhs, std::vector<int> const& rhs )
   {
      assert( lhs.size() == rhs.size() );
      for (std::vector<int>::size_type i = 0; i < lhs.size; ++i )
         lhs[i] += rhs[i];
      return lhs;
   }
};

If you want to do that with iterators, it is again similarly simple:

struct PlusVal
{
   std::vector<int> operator()( std::vector<int> lhs, std::vector<int> const& rhs )
   {
      assert( lhs.size() == rhs.size() );
      std::vector<int>::iterator it = lhs.begin(), end = lhs.end();
      std::vector<int>::const_iterator rit = rhs.begin();
      while ( it != end )
         *it++ += *rit++;
      return lhs;
   }
};

You're looking for the std::vector::const_iterator type

std::vector<int> operator() (const std::vector<int>& x, const std::vector<int>& y)
{
  std::vector<int> result;

  // Not strictly necessary, but helps with performance a bit
  result.reserve(std::min(x.length(), y.length());

  for (std::vector<int>::const_iterator x_it = x.begin(),
                                      y_it = y.begin();
      x_it != x.end() && y_it != y.end();
      ++x_it, ++y_it)
  {
   result.push_back(*x_it + *y_it);
  }

  return result;
}

It looks like you've already gotten a reasonable answer or two; I'll just point out an alternative. Though I hesitate to mention it, std::valarray fits so well for this I just can't resist:

std::valarray<int> x;
std::valarray<int> y;

// code to populate x and y elided

x += y;

Ever few months (or so) I see something valarray would make so simple I find it truly regrettable that it's been lost and forgotten (then I think about things like slice, gslice, slice_array, indirect_array, etc., and wish I hadn't thought of it at all).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top