MKK
MKK

Reputation: 140

Creating and using func pointer to method of friend class

I have 2 classes:

enum class Enumtype
{
    typ1,
    typ2,
};

class A
{
private:
    retType Func1(arg1Type, arg2Type, arg3Type);
    retType Func2(arg1Type, arg2Type, arg3Type);
public:
    A();
    retType Func(Enumtype, arg1Type, arg2Type, arg3Type);
}

class B
{
private:
    arg1Type a;
    arg2Type b;
    arg3Type c;
public:
    int FunctionFromB(Enumtype);
}

So the primary use was this:

int B::FunctionFromB(Enumtype x)
{
    A* objectA;
    for(int i=0; i<whatever; i++)
    {
        objectA->Func(x, a+i, b+(2*i), c+(3*i));
    }
}
retType A::Func(Enumtype x, arg1type a, arg2type b, arg3type c)
{
    switch(x)
    {
    case Enumtype::typ1:
        return Func1(a, b, c);
    case Enumtype::typ2:
        return Func2(a, b, c);
    default:
        return Func1(a, b, c);
    }
}

Unfortunately I do not want to run switch every loop and so I thought about this:

How to do this? I tried to do this with std::function, but I don't know how to properly declare/initialize/call it to make it work.

EDIT:
I've edited FunctionFromB, because I've skipped one important part -> Func was called in loop with different args.

EDIT2:
Help was given and I have answer saying how to do this with C-style function ptr, yet I want to make it work with std::function. I made it like that (note that class B and enum are the same):

class A
{
private:
    retType Func1(arg1Type, arg2Type, arg3Type);
    retType Func2(arg1Type, arg2Type, arg3Type);
public:
    A();
    typedef std::function<retType(arg1Type, arg2Type, arg3Type)> funcPtr;
}

int B::FunctionFromB(Enumtype typeB)
{
    A* objectA;
    A::funcPtr func = nullptr;

    switch(type)
    {
    case Enumtype::typ2:
        func = std::bind(&A::Func2, objectA, std::placeholders::_1,
                            std::placeholders::_2, std::placeholders::_3);
        break;
    case Enumtype::typ2:
    default:
        func = std::bind(&A::Func1, objectA, std::placeholders::_1,
                            std::placeholders::_2, std::placeholders::_3);
        break;
    }

    for(int i=0; i<whatever; i++)
        func(a+i, b+(2*i), c+(3*i));
}

and I guess, it works. If anyone finds an error in here or a better way, please do tell me ;)

Upvotes: 0

Views: 77

Answers (1)

Serge Ballesta
Serge Ballesta

Reputation: 149075

Could you use an unscoped enum for EnumType?

enum Enumtype
{
    enumtyp1,
    enumtyp2,
    enumtypmax
};

If it is an option, the compiler offers you for free a conversion to int : enumtyp1 -> 0, enumtyp2 -> 1,enumtypmax -> 2 (per 3.9.2 § 10 The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by integral promotion)

The values are guaranteed per 3.9.2 §2 The identifiers in an enumerator-list are declared as constants, and can appear wherever constants are required. An enumeratordefinition with = gives the associated enumerator the value indicated by the constant-expression. If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one.

enum { a, b, c=0 };
enum { d, e, f=e+2 };

defines a, c, and d to be zero, b and e to be 1, and f to be 3.

You could then build a static array of A methods in A and use a direct array index that should be simpler than a switch :

enum Enumtype
{
    enumtyp1,
    enumtyp2,
    enummax
};

class A
{
private:
    typedef retType (__thiscall A::*funcx)(arg1Type,arg2Type,arg3Type);
    retType Func1(arg1Type, arg2Type, arg3Type);
    retType Func2(arg1Type, arg2Type, arg3Type);
    static funcx fp[enummax];
public:
    A();
    retType Func(Enumtype, arg1Type, arg2Type, arg3Type);
};

class B
{
private:
    arg1Type a;
    arg2Type b;
    arg3Type c;
public:
    int FunctionFromB(Enumtype);
};

int B::FunctionFromB(Enumtype x)
{
    A* objectA;
    for(int i=0; i<whatever; i++)
    {
        objectA->Func(x, a+i, b+(2*i), c+(3*i));
    }
    return whatever;
}
retType A::Func(Enumtype x, arg1Type a, arg2Type b, arg3Type c)
{
    funcx f = A::fp[x];
    return (this->*fp[x])(a, b, c);
}

A::funcx A::fp[enummax] = { &A::Func1, &A::Func2 };

Alternatively, you could get directly a pointer in B::FunctionFromB and directly call it repeatedly :

enum Enumtype
{
    enumtyp1,
    enumtyp2,
    enummax
};

class A
{
public:
    typedef retType (__thiscall A::*funcx)(arg1Type,arg2Type,arg3Type);
private:
    retType Func1(arg1Type, arg2Type, arg3Type);
    retType Func2(arg1Type, arg2Type, arg3Type);
    static funcx fp[enummax];
public:
    A();

    friend class B;
};

class B
{
private:
    arg1Type a;
    arg2Type b;
    arg3Type c;
    A::funcx getFunc(Enumtype);
public:
    int FunctionFromB(Enumtype);
};

A::funcx B::getFunc(Enumtype x){
    return A::fp[x];
}

int B::FunctionFromB(Enumtype x)
{
    A* objectA;
    A::funcx funcPtr = getFunc(x);
    for(int i=0; i<whatever; i++)
    {
        (objectA->*funcPtr)(a+i, b+(2*i), c+(3*i));
    }
    return whatever;
}

A::funcx A::fp[enummax] = { &A::Func1, &A::Func2 };

In that latter case, you could avoid declaring the array of methods in A, stick to a scoped enum for EnumType and use the switch once per call to B::FunctionFromB :

A::funcx B::getFunc(Enumtype x){
    switch (x) {
        case EnumType::typ1:
            return &A::Func1;
        case EnumType::typ2:
            return &A::Func2;
        case default:
            return &A::Func1;
    }
}

Upvotes: 1

Related Questions