tags:

views:

170

answers:

3

I have this code which compiles and works as expected:

class Right
{};

class Left
{
public:
  Left& operator = (Right const&)
  {
    //... Do something ...

    return *this;
  }
};


int main()
{
  Right right;
  Left left;

  // Assign individual object -- this works
  left = right;
}

But now, this one surprises me, I thought the template would work itself out since I already provided the = operator() to the Left class.

int main()
{
  ...

  std::list<Right> rightLst;
  std::list<Left>  leftLst;

  // Assign a list of objects -- this doesn't compile
  leftLst = rightLst;
}

What can I do so that I could convert the rightLst to leftLst conversion in a single line?

Also, what if explicit keyword is used on Left? Then none of the proposed solutions will work, i.e. if Left is defined as:

class Left
{
public:
  Left()
  {}
  explicit Left(Right const& right_)
  {
    .. // Do something ..
  }
  Left& operator = (Right const& right_)
  {
    // .. Do something ..
    return *this;
  }
};

See, I'm trying to avoid writing this code below to achieve what I want to do:

  for(std::list<Right>::iterator it  = rightLst.begin();
                                 it != rightLst.end();
                                 it++ )
  {
    leftLst.push_back(Left(*it));
  }

What code from STL I could re-use to replace the above?

+1  A: 

What if you add a copy constructor to Left?

class Left
{
public:
  Left(Right const&)
  { // .. do something similar to operator =
  }
  Left& operator = (Right const&)
  //...

EDIT: Okay, since the copy constructor doesn't fix it, then you can't just use an = list-to-list assignment.

Try:

Left left(right.begin(), right.end());

or:

left.assign(right.begin(), right.end());

P.S. Either way, you still need a copy constructor that takes a const Right&.

Mike DeSimone
I tried this, and still gets the same compiler error.
ShaChris23
+8  A: 

Use:

 std::copy(rightLst.begin(), rightLst.end(), std::back_inserter(leftLst));

This will add new elements to the end of leftLst corresponding to the elements in rightLst. You will need to add a constructor to Left that takes const Right &.

If leftLst and rightLst already contain the same number of elements and you want to overwrite the elements in leftLst, use:

std::copy(rightLst.begin(), rightLst.end(), leftLst.begin());

Edit:

Even simpler is to use:

leftLst.assign(rightLst.begin(), rightLst.end());

This will replace all elements (if any) in leftLst, so it will cover both cases given above.

The reason that the normal assignment operator doesn't work here is that the standard defines it to only accept a list of the same type, so it won't allow assigning from list<Right> to list<Left>.


If the constructor is declared explicit, there won't be a way for the assign function to know how to convert Right to Left, so it won't work. Another option is to define a conversion operator on Right instead:

Right::operator Left() { return Left();}

If you do neither, assign will fail to compile.

The second version of copy given above will work without a conversion operator or a conversion constructor (only an assignment operator is needed), but it requires the target list to have enough elements.

interjay
@interjay - could you please explain wht the code above didn't work? (which was OP's actual question). Also, for STL newbies, why is your solution what should actually be used. Thx!
DVK
What if Left copy constructor is declared as explicit?
ShaChris23
The two lists are of different types [list<Right> and list<Left>], and there is no assignment operator to connect the two.
Dennis Zickefoose
@ShaChris23: I think a copy constructor cannot be explicit if you want to be able to use it.
UncleBens
@ShaChris23: It won't work if declared explicit, see my last edit.
interjay
+7  A: 

When you try to assign:

std::list<Right> rightLst;
std::list<Left>  leftLst;

leftList = rightList;

then the operator=() of std::list, not that of the contained type, is used. But the lists are of different types, and so cannot be assigned.

anon
operator=, not operator().
Paul
@Paul Thanks - fixed.
anon