Шаблонный метод-оболочка для других методов класса - PullRequest
3 голосов
/ 15 июня 2019

Я пытаюсь создать шаблонную оболочку для разных функций с разными параметрами. Установка представляет собой класс A с базовой реализацией двух методов foo и bar. Другой класс B должен обернуть эти методы и добавить новые функциональные возможности.

Решение по следующей ссылке очень хорошо работает для неклассовых функций: c ++ 11: шаблонная функция оболочки

Но если я пытаюсь вызвать методы из другого класса, я получаю сообщение об ошибке.

#include <algorithm>
#include <functional>
#include <iostream>

class A
{
public:
    void foo(int x) {
        std::cout << "Foo: " << x << std::endl;
    }

    void bar(int x, float y) {
        std::cout << "Bar: " << x << ", " << y << std::endl;
    }
};

class B
{
public:
    void fooAndMore(int x) {
        foobarWrapper(&A::foo, 1);
    }

    void barAndMore(int x, float y) {
        foobarWrapper(&A::bar, 1, 3.5f);
    }

    template<typename  T, typename... Args>
    void foobarWrapper(T&& func, Args&&... args)
    {
        std::cout << "Start!" << std::endl;
        std::forward<T>(func)(std::forward<Args>(args)...);
        std::cout << "End!" << std::endl;
    }
};

int main()
{
    B b;
    b.fooAndMore(1);
    b.barAndMore(2, 3.5f);
}

Я ожидаю что-то подобное:

Start!
Foo: 1
End!
Start!
Bar: 1, 3.5
End!

Но вместо этого я получаю:

error C2064: term does not evaluate to a function taking 1 arguments
note: see reference to function template instantiation 'void B::foobarWrapper<void(__thiscall A::* )(int),int>(T &&,int &&)' being compiled
    with
    [
        T=void (__thiscall A::* )(int)
    ]

error C2064: term does not evaluate to a function taking 2 arguments
note: see reference to function template instantiation 'void B::foobarWrapper<void(__thiscall A::* )(int,float),int,float>(T &&,int &&,float &&)' being compiled
    with
    [
        T=void (__thiscall A::* )(int,float)
    ]

Есть идеи, как это решить?

Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 15 июня 2019

Самое простое решение - сделать функции-члены класса A равными static. ( См. Онлайн )

class A
{
public:
    static void foo(int x) {
    ^^^^^^
        std::cout << "Foo: " << x << std::endl;
    }

    static void bar(int x, float y) {
    ^^^^^^
        std::cout << "Bar: " << x << ", " << y << std::endl;
    }
};

В противном случае вам необходимо передать экземпляр класса A для вызова его функций-членов в функции foobarWrapper.Используя лямбды, вы можете упаковать их в вызываемый номер func и передать в foobarWrapper.

( см. Онлайн )

class B
{
public:
    void fooAndMore(const A& a_obj, int x) {
        foobarWrapper([&]() { return a_obj.foo(x); });
        //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Args captured to the lambda
    }

    void barAndMore(const A& a_obj, int x, float y) {
        foobarWrapper([&]() { return a_obj.bar(x, y); });
        //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Args captured to the lambda
    }

    template<typename  T>
    void foobarWrapper(T&& func)   // no Args needed any more (@credits Jarod42)
    {
        std::cout << "Start!" << std::endl;
        std::forward<T>(func)();   // simply call the func
        std::cout << "End!" << std::endl;
    }
};

int main()
{
    B b;
    b.fooAndMore(A{}, 1);       // pass a temporary A object
    b.barAndMore(A{}, 2, 3.5f);
}
1 голос
/ 15 июня 2019

Попробуйте это,

#include <algorithm>
#include <functional>
#include <iostream>

class A
{
public:
    void foo(int x) {
        std::cout << "Foo: " << x << std::endl;
    }

    void bar(int x, float y) {
        std::cout << "Bar: " << x << ", " << y << std::endl;
    }
};

class B
{
public:
    void fooAndMore(int x) {
        foobarWrapper(&A::foo, x);
    }

    void barAndMore(int x, float y) {
        foobarWrapper(&A::bar, x, y);
    }

    template<typename  T, typename... Args>
    void foobarWrapper(T func, Args&&... args)
    {
        std::cout << "Start!" << std::endl;

        auto caller = std::mem_fn( func); // Newly added lines
        caller( A(), args...);  // Newly added line

        std::cout << "End!" << std::endl;
    }
};

int main()
{
    B b;
    b.fooAndMore(1);
    b.barAndMore(2, 3.5f);
}

выход:

Start!
Foo: 1
End!
Start!
Bar: 2, 3.5
End!

Для получения более подробной информации см. Эту ссылку std :: mem_fn

...