Search code examples
c++templatesstdlist

How to add supported types to existing legacy std::list manipulation functions (i.e. templates?)


I have a specific question about adding supported types to existing legacy std::list manipulation functions. I tried to do this with templates without success, so I'd appreciate any advice on how to use templates better or use different mechanisms entirely. Please take a look at my scenario below and let me know if there's any thoughts on this. Thanks in advance for any help!

I currently have two std::lists of type A, and have insertion/removal/getter/etc functions for them. A simplified code snippet for this is shown below.

typedef std::list<A*> TListA;
TListA ListA1;
TListA ListA2;

void InsertIntoListA(A* pA)
{
    TListA& ListA = IsBoo()? ListA1 : ListA2;
    ListA.push_back(pA);
}

Now, it turns out I need to add type B, and I considered using templates to add this new type (as shown below), but it turns out there are two issues with that.

template <typename T>
void InsertIntoListT(T* pT)
{
    std::list<T*>& List;

    if (IsA())
        List = IsBoo()? ListA1 : ListA2;
    else
        List = IsBoo()? ListB1 : ListB2;      

    List.push_back(pT);   
}

Issue 1: I cannot have "std::list& List" because since it's by reference, it needs to be assigned to an actual list. So I would end up with something like this, which is not ideal.

template <typename T>
void InsertIntoListT(T* pT)
{    
    if (IsA()) {
        TListA& ListA = IsBoo()? ListA1 : ListA2;
        ListA.push_back(pT);   
    } else {
        TListB& ListB = IsBoo()? ListB1 : ListB2;      
        ListB.push_back(pT);   
    }     
}

Issue 2: I am getting type conversion errors with either A to B, or B to A. I think this is because given the template T, the compiler will enumerate all four possibilities for "ListA.push_back" and "ListB.push_back," which leads to inserting A to list A, inserting B to list A, inserting A to list B, and inserting B to list B, and only two of these are valid. So I end up with something like this, which I think defeats the purpose of using templates.

template <typename T>
void InsertIntoListT(T* pT)
{    
    if (IsA()) {
        TListA& ListA = IsBoo()? ListA1 : ListA2;
        ListA.push_back(reinterpret_cast<A*>(pT));
    } else {
        TListB& ListB = IsBoo()? ListB1 : ListB2;      
        ListB.push_back(reinterpret_cast<B*>(pT));
    }     
}

Solution

  • Don't mix all in one function. It's very bad practice. Use something like

    void InsertIntoListImpl(A* p)
    {
       (IsBoo() ? ListA1 : ListA2).push_back(p);
    }
    
    void InsertIntoListImpl(B* p)
    {
       (IsBoo() ? ListB1 : ListB2).push_back(p);
    }
    
    template<typename T>
    void InsertIntoList(T* p)
    {
       InsertIntoListImpl(p);
    }
    

    or some traits, or something else. But anyway, not many conditions in one function.

    Any why not pass actual list to function for insert? It will be better.