0

Let's say I have the following C++ code:

#ifndef _XMaster_
#define _XMaster_
class XMaster
{
public:
    XMaster(string A, string B, string C)
    {
        nM = A;
        oC = B;
        nI = C;
    }

    string nM;
    string oC;
    string nI;

    vector<int> TSNRay;
    vector<int> TSNFor;
};
#endif

void Hershika(vector<XMaster> &Tapren, size_t IS);

int Main()
{
    vector<XMaster> Tapren;

    // Let's just say I have x number of elements in Tapren vector and the vector 
    // data members TSNRay and TSNFor both filled

    size_t IS = 0;

    for(IS; IS < Tapren.size(); ++IS)
    {
        Hershika(Tapren, IS);
    }

    return 0;
}

void Hershika(vector<XMaster> &Tapren, size_t IS)
{
    vector<int>::const_iterator AIT;

    if(!Tapren[IS].TSNRay.empty())
    {
        for (AIT = Tapren[IS].TSNRay.begin() ; 
            AIT != Tapren[IS].TSNRay.end(); ++AIT)
        {
            AnDt(Tapren, *AIT, IS);         
        }
    }   
}

My question is how to make function Hershika works with either data members TSNRay or TSNFor since they are both of the same type? As shown, it can only access TSNRay. When calling it, how can I specify that I need to pass TSNRay or TSNFor?

Thank you!

Xigma
  • 177
  • 1
  • 11

1 Answers1

1

Using pointer-to-member

typedef vector<int> XMaster::* XMasterVectorPtr;

void Hershika(vector<XMaster> &Tapren, XMasterVectorPtr member, size_t IS);

void Hershika(vector<XMaster> &Tapren, XMasterVectorPtr member, size_t IS)
{
    vector<int>::const_iterator AIT;

    if(!(Tapren[IS].*member).empty())
    {
        for (AIT = (Tapren[IS].*member).begin() ; 
            AIT != (Tapren[IS].*member).end(); ++AIT)
        {
            AnDt(Tapren, *AIT, IS);         
        }
    }   
}

You would call it like this:

Hershika(Tapren, &XMaster::TSNRay, IS);
Hershika(Tapren, &XMaster::TSNFor, IS);

There are a few different ways you could rewrite it without using pointers to members, such as just accepting a reference to both the vector<XMaster> and the vector<int> you want to process. This may allow you to eliminate the IS parameter, if AnDt() does not require it. (It's hard to tell without being able to see that function.)

Using a reference to the target vector

A second option is simply to require a reference to the vector<int> on which you need to operate.

void Hershika(vector<XMaster> &Tapren, vector<int> const &member, size_t IS);

void Hershika(vector<XMaster> &Tapren, vector<int> const &member, size_t IS)
{
    vector<int>::const_iterator AIT;

    if(!member.empty())
    {
        for (AIT = member.begin() ; AIT != member.end(); ++AIT)
        {
            AnDt(Tapren, *AIT, IS);         
        }
    }   
}

Calling it like this:

Hershika(Tapren, Tapren[IS].TSNRay, IS);
Hershika(Tapren, Tapren[IS].TSNFor, IS);

Using lambdas

This is a C++11-only approach, but it can be used in two places to significantly reduce the size of the code while improving readability.

template <typename Selector>
void Hershika(vector<XMaster> &Tapren, Selector selector, size_t IS)
{
    auto const & member = selector(Tapren);

    std::for_each(member.begin(), member.end(),
        [&Tapren, IS] (int i) { AnDt(Tapren, i, IS); });
}

Called like this:

Hershika(Tapren, [] (XMaster &x) { return x.TSNRay; }, IS);
Hershika(Tapren, [] (XMaster &x) { return x.TSNFor; }, IS);
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • Thanks a lot for your proposed solution. Regarding the second proposal, AnDt() does require IS; may you please elaborate with some code snippets. – Xigma Oct 29 '14 at 22:08
  • @Xigma I've added a few alternatives that might help. If you can use lambdas then you can reduce the whole function to a single `std::for_each` but of course that doesn't do much in the way of code reuse. – cdhowie Oct 30 '14 at 01:12
  • Thanks again for your clarifications. I find the reference to the target vector solution to be quite clean and readable. I also liked the lambda one; good that my compiler supports it. – Xigma Oct 30 '14 at 19:36
  • @Xigma NP. Note that your `if (!member.empty())` test is redundant because `member.begin() == member.end()` when the vector is empty, so the `for` loop will never iterate anyway. If the vector is empty it may save a few CPU cycles but unless you process empty vectors *a lot* then it is unlikely to be worth the extra code it introduces. – cdhowie Oct 30 '14 at 20:12