0

I have a list of tuples and need to remove elements from the list, something like this:

enum class test
{
    mem1,
    mem2,
    mem3,
    mem4
};

struct A
{

};

int main()
{
    std::list<std::tuple<int, test, A>> tuple_list;

    // fill list with random objects
    for (int i = 0; i < 4; i++)
    {
        tuple_list.push_back(
               std::forward_as_tuple(i, static_cast<test>(i), A()));
    }

    // now remove it
    for (auto& ref : tuple_list)
    {
        tuple_list.remove(ref); // error C2678
    }
    return 0;
}

error C2678: binary '==': no operator found which takes a left-hand operand of type 'const _Ty' (or there is no acceptable conversion)

How do I remove tuple elements from the list in above example?

EDIT:

I tried following method, it compiles just fine unlike previous example but there is runtime assertion:

int main()
{
    list<tuple<int, test, A>> tuple_list;

    for (int i = 0; i < 4; i++)
    {
        tuple_list.push_back(
                std::forward_as_tuple(i, static_cast<test>(i), A()));
    }

    for (auto iter = tuple_list.begin(); iter != tuple_list.end(); iter++)
    {
        tuple_list.erase(iter);
    }
}

Expression: can not increment value initialized list iterator

  • 1
    The second one blows up because `erase` removes the iterator from the list. `iter++` is kinda invalid after that. You could `iter = tuple_list.erase(iter);` and remove the `iter++`. – user4581301 Mar 31 '19 at 05:20
  • man that worked!! thanks, but I'm still interested what can be done to use ranged for loop from 1st example. –  Mar 31 '19 at 05:22

1 Answers1

0

First off, you don't want to do this. Removing items from a list (or any container) in the middle of a range-based for is a recipe for disaster as hidden behind the for loop are iterators that will be invalidated as soon as the item is removed.

This is the same problem as the second experiment with

for (auto iter = tuple_list.begin(); iter != tuple_list.end(); iter++)
{
    tuple_list.erase(iter); // iter rendered invalid. 
                            // That makes iter++ and iter != tuple_list.end()
                            // totally bogus.
}

This version can be fixed with

for (auto iter = tuple_list.begin(); iter != tuple_list.end(); /* nothing here */)
{
    iter = tuple_list.erase(iter); // iter updated here
}

or a

while (! tuple_list.empty()) 
{
     tuple_list.pop_front();
}

Or

tuple_list.clear();

OK. On to what went wrong:

error C2678: binary '==': no operator found which takes a left-hand operand of type 'const _Ty' (or there is no acceptable conversion)

means that one of the parts of the tuple cannot be compared for equality.

struct A
{

};

has no equality operator. Solution is to add one.

struct A
{
}; 

bool operator==(const A& lhs, const A& rhs)
{ 
    Comparison logic goes here 
}    

Useful additional reading:

The Erase-Remove idiom can be used to solve similar problems.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • sorry I'm new to this, how and where do I use comparison operator? –  Mar 31 '19 at 05:35
  • @zebanovich I'm mid-edit. I stupidly told you how to do it without telling you not to do it because it'll blow up at runtime. `operator==` gets used for you. The error message is code deep inside `remove` looking for `==`. Have better answer up in a minute. – user4581301 Mar 31 '19 at 05:38
  • @user4581301 shouldn't the operator overload be inside the struct? Or does that not matter? – Olivier Samson Mar 31 '19 at 05:41
  • @OlivierSamson it can be, but the idiomatically preferred approach is to use a free function. See [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) for explanation and further wisdom. – user4581301 Mar 31 '19 at 05:47
  • wait, do I just put the operator somewhere in the source file and compiler will pick it up for comparison? –  Mar 31 '19 at 05:54
  • 1
    So long as the operator is declared before the first time it gets used the compiler knows it exists and will use it. – user4581301 Mar 31 '19 at 05:57