Hello All,

i am trying to tidy-up some code and i'm not completely sure how this can be done. What i have is this:
(This is some sort of psuedocode that i just wrote to explain the problem, not proper code)

void foo1(typeofList1 list1)
{
   for (i = 0; i < list1.size) {
       // iterate through listOfToys
       for (j = 0; j < list1->listOfToys; j++) {
           // do some stuff
       }
   }
}

void foo2(typeofList2 list2)
{
   for (i = 0; i < list2.size) {
       // iterate through listOfApples
       for j = 0; j < list2->listOfApples; j++) {
           // do some stuff
       }
   }
}

void genericFoo(genericList genList)
{
   for (i = 0; i < genList.size) {

       // How do i do the iteration here?
   }
}

int main()
{
   foo1(listOfItems1);
   foo2(listOfItems2);

   // this is what i need:, but problem with accessing the lists that they internally have.
   genericFoo(listOfItems1);
   genericFoo(listOfItems2);

   return 0;
}

I plan on writing a single function to do the job of foo1 and foo2.
But, these two have different lists in them. So, i have a problem iterating the second list. I'm not sure how this can be solved. Can anyone please provide some hints/ideas? I hope i have explained the problem clearly

Thanks!

Edited 4 Years Ago by myk45

Well you could make a base class that has a generic function called getList() that would display the list. Then you could derive your differnt kinds of list from that base class. then the foo() function will get passed a pointer to the base class so it can except both sub list. In the foo() function you would then call the getList of the pointed to object

Comments
thanks!

Somthing like this perhaps

template<typename FirstContainer, typename SecondContainer, typename BinaryOp>
void iterateTwoContainer(const FirstContainer& firstList,
                         const SecondContainer& secondList,
                         const BinaryOp op2){
 for(int i = 0; i < firstList.size(); ++i){
   for(int j = 0; j < secondList.size(); ++j){
     op2(firstList[i],secondList[j]);
   }
 }
}

void handleItemAndToys(const Item1& item, const Toy& toy){/*...*/}
void handleItemAndApples(const Item2& item,const Apple& apple){ /*...*/}
int main(){

   iterateTwoContainers(listOfItem1,listOfToys,handleItemAndToys);
   iterateTwoContainers(listOfItem2,listOfAppels,handleItemAndApples);
}
Comments
thanks!

@NathanOliver:
Thanks for the suggestion. Well i have not written the classes for these lists. I am just creating a list of them. So, i'm not sure if could modify the classes themselves.

@firstPerson:
Thanks! The first list contains the second list in it, so i cannot really use the approach that you have suggested. Also, i was planning on having a single function do everything.

I have come up with this: But it's still not good:

template<typename Container>
void genericFoo(Container genList)
{
   for (i = 0; i < genList.size) {
       // do stuff with the list.
       // list here is either listOfToys   from  listOfItems1
       //                  or listOfApples from listOfItems2           
   }
}

int main()
{
   for (int i = 0; i < listOfItems1.size(); i++)
       genericFoo(listOfItems1[i]->listOfToys);

   for (int i = 0; i < listOfItems2.size(); i++)
       genericFoo(listOfItems2[i]->listOfApples);

   return 0;
}

This is still not so clean, but i couldn't think of any other way :(

You could just use a pointer to a data member of the class held by the upper-level list. In other words, you can use this:

template <typename TopContainer, typename TopElement, typename BottomContainer>
void genericFoo(const TopContainer& topList, BottomContainer TopElement::* bottomList) {
  for (auto it = topList.begin(); it != topList.end(); ++it) {
    // ...
    const BottomContainer& list2 = (*it).*bottomList;
    for (auto it2 = list2.begin(); it2 != list2.end(); ++it2) {
       // do some stuff
    }
  }
};

Then, call it like this:

int main() {

  genericFoo(listOfItems1, &listOfItems1::value_type::listOfToys);
  genericFoo(listOfItems2, &listOfItems2::value_type::listOfApples);

  // or:
  genericFoo(listOfItems1, &Item1Type::listOfToys);
  genericFoo(listOfItems2, &Item2Type::listOfApples);

};

Enjoy!

Comments
thanks!

Thanks mike_2000_17! I'm not completely sure if i can use C++ 11 features due to some restrictions, but thanks for the excellent suggestion. That is exactly what i was looking for :)

Yeah, the C++11 feature I used (the auto keyword) was just to save space and keep the example cleaner. It's not needed of course.

Comments
agreed

Hi mike_2000_17,

I just tried a sample code of what you had given on this online compiler. i am getting an error while making the function call. This is the first time i'm using a pointer to a data member. i wrote some sample code:

template <typename TopContainer, typename TopElement, typename BottomContainer>
void genericFoo(const TopContainer& topList, BottomContainer TopElement::* bottomList) 
{
    for (auto it = topList.begin(); it != topList.end(); ++it) {
        // ...
        const BottomContainer& list2 = (*it).*bottomList;
        for (auto it2 = list2.begin(); it2 != list2.end(); ++it2) {
            // do some stuff
        }
    }
}

struct listA {
    std::vector<char> listOfApples;    
};

struct listB {
    std::vector<int> listOfToys;
};

std::vector< std::vector<listA> > listOfItems1;
std::vector< std::vector<listB> > listOfItems2;


int main()
{
    std::vector<int> listB::*pList = &listB::listOfToys;
    genericFoo(listOfItems1, pList);
    return 0;
}

I have compiled it link

I am getting the following error:

prog.cpp: In function 'void genericFoo(const TopContainer&, BottomContainer TopElement::*) [with TopContainer = std::vector<std::vector<listB> >, TopElement = listB, BottomContainer = std::vector<int>]':
prog.cpp:30:35:   instantiated from here
prog.cpp:8:47: error: pointer to member type 'std::vector<int>' incompatible with object type 'std::vector<listB>'

Could you please let me know what is wrong with this? I'm also reading up on "pointer to data members"
Thanks!

Edited 4 Years Ago by myk45

Why are your listOfItems object vectors of vectors? From all your previous examples, it seems to me that it should just be vectors, as so:

std::vector<listA> listOfItems1;
std::vector<listB> listOfItems2;

And when you use that, it works fine. If you wanted to use vectors of vectors of object which also contain a data member that is a vector (or container of some sort), then you'll need to change the loops in the function (to have three nested loops, with only the most nested loop that uses the container referred to by the pointer to data member).

I'm also reading up on "pointer to data members"

Yeah, pointer to data members are not very popular / well-known. They are generally not that useful, but it's good to be aware of that possibility, because once in a while you stumble upon a problem like the one in this thread, and they can provide an elegant solution. Did you know that pointers to data members (as well as to member functions) can also serve as template arguments? Not that it's useful in this particular case, but it's a neat trick.

Thanks a lot mike_2000_17! Yeah, my bad, the example i gave shouldn't have had the outer vector. And i am now getting a hold of the pointer to data member. This is what i had wanted so many times earlier, but never knew of it. It's quite awesome!

Also, i read that C doesn't support it. Any particular reason for it?
PS: should i create a new thread for this since it is C specific?

Thanks!

This question has already been answered. Start a new discussion instead.