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

StackOverflow https://stackoverflow.com/questions/14557375

  •  05-03-2022
  •  | 
  •  

سؤال

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));
    }     
}
هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

Obviously, you can't do the list type switch inside the function template, because each template instantiation is only aware of one of the two types. So you have to do the switch outside the function. Here's a possibility:

TListA& getList(bool isBoo, A* /*dummy*/)
{
  return isBoo ? ListA1 : ListA2;
}

TListB& getList(bool isBoo, B* /*dummy*/)
{
  return isBoo ? ListB1 : ListB2;
}

template <typename T>
void InsertIntoListT(T* pT)
{    
  auto& theList = getList(IsBoo(), (T*)NULL);
  theList.push_back(pT);
}

The dummy is only for type siwtching - could be done via a function template and a specialization but thats ugly. Depending on the real nature of your List variables the getList functionality can be written by other means. Maybe more generic, maybe not.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top