c++17function-pointerspointer-to-memberstd-functionstdbind

How to pass a pointer to member function to a template function


Here is my simplified code: S.h

class SBase {
...
public: 
    virtual std::vector<int32_t> getNumbersSet1();
    virtual std::vector<int32_t> getNumbersSet2();

}

class SDerived : public SBase {
...
public: 
    virtual std::vector<int32_t> getNumbersSet1() override;
    virtual std::vector<int32_t> getNumbersSet2() override;
}

class Base {
  public:
    virtual std::vector<int32_t> getNumbersSet1();
    virtual std::vector<int32_t> getNumbersSet2();
  protected:
    std::vector<SBase> sVec;

};

class Derived : public Base {
  public:
    virtual std::vector<int32_t> getNumbersSet1() override;
    virtual std::vector<int32_t> getNumbersSet2() override;
  protected:
    std::vector<SDerived> sVec;

}

Here is my simplified source code: S.cpp

std::vector<int32_t> Base::getNumbersSet1() {
    std::vector<int32_t> ret;
    for (SBase const& sbase : sVec)
    {
        std::vector<int32_t> tmp = sbase.getNumbersSet1();
        retval.insert(retval.end(), tmp.cbegin(), tmp.cend());
    }
    return retval;
}

std::vector<int32_t> Base::getNumbersSet2() {
    std::vector<int32_t> ret;
    for (SBase const& sbase : sVec)
    {
        std::vector<int32_t> tmp = sbase.getNumbersSet2();
        retval.insert(retval.end(), tmp.cbegin(), tmp.cend());
    }
    return retval;
}

std::vector<int32_t> Derived::getNumbersSet1() {
    std::vector<int32_t> ret;
    for (SDerived const& sderived : sVec)
    {
        std::vector<int32_t> tmp = sderived.getNumbersSet1();
        retval.insert(retval.end(), tmp.cbegin(), tmp.cend());
    }
    return retval;
}

std::vector<int32_t> Derived::getNumbersSet2() {
    std::vector<int32_t> ret;
    for (SDerived const& sderived : sVec)
    {
        std::vector<int32_t> tmp = sderived.getNumbersSet2();
        retval.insert(retval.end(), tmp.cbegin(), tmp.cend());
    }
    return retval;
}

Now, in order to remove some code duplicates I want to create a template function getNumbersSet() in my Base class, with a view to be able to call it from both getNumbersSet1() and getNumbersSet2() for both Base class and Derived class:

in the source file:

std::vector<int32_t> Base::getNumbersSet1() {
    return Base::getNumbersSet<SBase>(sVec, &Base::getNumbersSet1);
}

std::vector<int32_t> Base::getNumbersSet2() {
    return Base::getNumbersSet<SBase>(sVec, &Base::getNumbersSet2);
}

std::vector<int32_t> Derived::getNumbersSet1() {
    return Base::getNumbersSet<SDerived>(sVec, &Derived::getNumbersSet1);
}

std::vector<int32_t> Derived::getNumbersSet2() {
    return Base::getNumbersSet<SDerived>(sVec, &Derived::getNumbersSet2);
}

In order to achieve that This is what I have written the Base::getNumbersSet in the base class:

class Base {
    //.... as before
    
    template<class T>
    static std::vector<int32_t> getNumbersSet(std::vector<T> const& svec, std::vector<int32_t>(T::* getNumberFunc)() const )) {
        std::vector<int32_t> retval;
        for (T const& a : svec)
        {
            auto getNumbersOfT = std::bind(&T::getNumberFunc, a); // problem here
            std::vector<int32_t> tmp = getNumbersOfT();
            retval.insert(retval.end(), tmp.cbegin(), tmp.cend());
        }
    }

};

but this won't compile as on the problem line it complains that getNumberFunc is not a member function of type SBase or SDerived.

I have tried to use std::function, std::mem_fn as well but could not get it to work. I hope I have not made too many mistakes when reducing and my code and typing to post here. I appreciate your help.


Solution

  • A couple of problems: you want to be passing &SBase::getNumbersSet1 etc. as your function arguments, not &Base::getNumberSet1; and your pointer-to-member dereference syntax is wrong. You could change it to std::bind(getNumberFunc, a), or just call it like (a.*getNumberFunc)().

    Here is your code with those changes, compiling: https://godbolt.org/z/o8Kc9oxjG

    #include <cstdint>
    #include <vector>
    
    class SBase {
    public: 
        virtual std::vector<int32_t> getNumbersSet1() const { return {1, 2}; }
        virtual std::vector<int32_t> getNumbersSet2() const { return {2, 3}; }
    };
    
    class SDerived : public SBase {
    public: 
        virtual std::vector<int32_t> getNumbersSet1() const override { return {1, 2, 3}; }
        virtual std::vector<int32_t> getNumbersSet2() const override { return {2, 3, 4}; }
    };
    
    class Base {
      public:
        virtual std::vector<int32_t> getNumbersSet1();
        virtual std::vector<int32_t> getNumbersSet2();
        template<class T>
        static std::vector<int32_t> getNumbersSet(std::vector<T> const& svec, std::vector<int32_t>(T::* getNumberFunc)() const ) {
            std::vector<int32_t> retval;
            for (T const& a : svec)
            {
                std::vector<int32_t> tmp = (a.*getNumberFunc)();
                retval.insert(retval.end(), tmp.cbegin(), tmp.cend());
            }
            return retval;
        }
      protected:
        std::vector<SBase> sVec;
    
    };
    
    class Derived : public Base {
      public:
        virtual std::vector<int32_t> getNumbersSet1() override;
        virtual std::vector<int32_t> getNumbersSet2() override;
      protected:
        std::vector<SDerived> sVec;
    
    };
    
    std::vector<int32_t> Base::getNumbersSet1() {
        return Base::getNumbersSet(sVec, &SBase::getNumbersSet1);
    }
    
    std::vector<int32_t> Base::getNumbersSet2() {
        return Base::getNumbersSet(sVec, &SBase::getNumbersSet2);
    }
    
    std::vector<int32_t> Derived::getNumbersSet1() {
        return Base::getNumbersSet(sVec, &SDerived::getNumbersSet1);
    }
    
    std::vector<int32_t> Derived::getNumbersSet2() {
        return Base::getNumbersSet(sVec, &SDerived::getNumbersSet2);
    }
    
    int main() {
        Derived hello{};
    }