0

I am trying to write this code below:

// Type your code here, or load an example.
#include <iostream>

class A
{
public:
    virtual void virFunc1(int a) = 0;
    virtual void virFunc2(int a) = 0;
    void func1(int a)
    {
        onTempFunc(this->virFunc1, a);
    }
    void func2(int a)
    {
        onTempFunc(this->virFunc2, a);
    }
private:
    template <typename ImplFunc, typename... Args>
    void onTempFunc(ImplFunc impl_func, Args&&... args)
    {
        impl_func(args...);
    }
};

class B : public A
{
public:
    void virFunc1(int a) override
    {
        std::cout << "virFunc1: " << a << std::endl;
    }

    void virFunc2(int a) override
    {
        std::cout << "virFunc2: " << b << std::endl;
    }
};

int main()
{
    auto* A = new B();
    A->func1(2);
    A->func2(3);
}

But the compilation is failing in godbolt: https://godbolt.org/z/dq4szorq7 with the error: error: invalid use of non-static member function 'virtual void'. Basically I want to pass a virtual method to a function template along with its arguments. The function template will call that virtual method inside it. The different virtual methods can have different function signatures, that is why I have made onTempFunc a function template. Is there a way in C++ to achieve this?

In78
  • 440
  • 4
  • 17
  • Replace `onTempFunc(this->virFunc1, a)` with `onTempFunc(&A::virFunc1, a)`. Also replace `impl_func(args...)` with `(this->*impl_func)(args...)`. See [answer](https://stackoverflow.com/a/73798684/12002570) and [working demo](https://godbolt.org/z/j1W4KMq5E). – Jason Sep 21 '22 at 09:48
  • Dupe: [Passing functions as parameters in C++](https://stackoverflow.com/questions/73775286/passing-functions-as-parameters-in-c). Also [How to call through a member function pointer?](https://stackoverflow.com/questions/12189057/how-to-call-through-a-member-function-pointer) – Jason Sep 21 '22 at 09:52
  • 1
    Consider using [`std::invoke`](https://en.cppreference.com/w/cpp/utility/functional/invoke) instead of trying to get member-pointer syntax correctly. – StoryTeller - Unslander Monica Sep 21 '22 at 09:53
  • @StoryTeller-UnslanderMonica Yes, `std::invoke` is used in the [dupe](https://stackoverflow.com/questions/73775286/passing-functions-as-parameters-in-c). – Jason Sep 21 '22 at 09:53

2 Answers2

1

The correct syntax for passing virFunc1 and virFunc2 as arguments would be to write &A::virFunc1 and &A::virFunc2 respectively as shown below.

Additionally, for calling/using the passed member function pointer we can use ->* as shown below:

class A
{
public:
    virtual void virFunc1(int a) = 0;
    virtual void virFunc2(int a) = 0;
    void func1(int a)
    {
//-----------------vvvvvvvvvvvv-------->changed this
        onTempFunc(&A::virFunc1, a);
    }
    void func2(int a)
    {
//-----------------vvvvvvvvvvvv------->changed this 
        onTempFunc(&A::virFunc2, a);
    }
private:
    template <typename ImplFunc, typename... Args>
    void onTempFunc(ImplFunc impl_func, Args&&... args)
    {
//-------vvvvvvvvvvvvvvvvvvvvvvvvvv------> used ->* for member function pointer
        (this->*impl_func)(args...);
    }
};

Working demo.

Also refer to Passing functions as parameters in C++

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Also, I have a related question. Should I use `std::forward` to forward the arguments here? – In78 Sep 21 '22 at 12:47
  • 1
    @In78 Yes you can use `std::forward` if you want to preserve the value category of the original passed arguments. For more detailed explanation, refer to [Why should I use std::forward?](https://stackoverflow.com/questions/26550603/why-should-i-use-stdforward). – Jason Sep 21 '22 at 13:02
1

You can use member function pointers.

This

onTempFunc(this->virFunc1, a);

is not correct syntax to get a member function pointer. And this

impl_func(args...);

is not correct syntax to call a member function via a member function pointer.

A member function pointer to virFunc1 is &A::virFunc1. And you can call it via (this->*impl_func)(args...);:

class A
{
public:
    virtual void virFunc1(int a) = 0;
    virtual void virFunc2(int a) = 0;
    void func1(int a)
    {
        onTempFunc(&A::virFunc1, a);
    }
    void func2(int a)
    {
        onTempFunc(&A::virFunc2, a);
    }
private:
    template <typename ImplFunc, typename... Args>
    void onTempFunc(ImplFunc impl_func, Args&&... args)
    {
        (this->*impl_func)(args...);
    }
};

Live Demo

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185