C++类成员函数的Functor模板

3
我写了一个小的函数对象类,应该能够通过隐藏静态包装函数和指向对象的void指针来调用类成员函数。下面的示例由于设置包装函数时出现错误而无法编译。我想要的是将类成员指针作为模板参数。有人知道那里出了什么问题吗?
我认为静态函数在调用成员函数时可能会有另一个问题。我不确定如何使用模板语法来解决这个问题。启用了C++11的gcc可以编译最简示例。
#include <iostream>

template<class TReturn, class... TParameter>
struct Functor {

    TReturn (*ptr)(void*, TParameter...);
    void     *object;

    template<class TObject, class TMemberFunction>
    static TReturn memberCaller(void *obj, TParameter... params) {
        TObject *c = static_cast<TObject*>(obj);
        return (c->*(TObject::TMemberFunction))(params...);
    }

    TReturn operator()(TParameter... params) {
        return ptr(object, params...);
    }
};

class Test {
public:
    void func(int a) {
        std::cout << a << std::endl;
    }
};

int main(int argc, const char **argv) {
    Functor<void, int> f;
    Test               t;

    f.object = &t;
    f.ptr    = &Functor<void, int>::memberCaller<Test, Test::func>;

    f(100);
}

1
你需要将一个指向Test类中你想要调用的成员函数的指针传递给FunctorTMemberFunction不是类型名称。实际上,你可以查找一下std::functionfastdelegate是如何实现的。 - user7860670
我忘了提到在这种情况下没有STL可用,因为我在嵌入式系统中使用它。 - Gustavo
相关链接:https://dev59.com/iW855IYBdhLWcg3wg0rC - Passer By
这与嵌入式系统有什么关系? - Lundin
2个回答

3
这个对你有用吗?
#include <iostream>

template<class TObject, class T, class... TParameter>
struct Functor {

    using TMemberFunction = T (TObject::*)(TParameter...);
    TMemberFunction ptr;
    TObject     *object;


    T operator()(TParameter... params) {
        return (object->*ptr)(params...);
    }
};

class Test {
public:
    void func(int a) {
        std::cout << a << std::endl;
    }
};

template<typename T>
class TD;

int main() 
{
    Functor<Test, void , int> f;
    Test               t;

    f.object = &t;
    f.ptr = &Test::func;

    f(100);
}

1
不要像提问一样回答问题。也许可以添加一些解释,而不仅仅是倾倒代码。 - GhostCat
这很好用,但我只能将Functor用于一个特定的类。有时候并不是类类型重要,而是函数原型。 - Gustavo
不同类的成员函数具有不同的类型。因此,我真的看不出“类类型不计”的可能性。 - Artemy Vysotsky

2

除了一些其他错误,您的代码在以下情况下无法处理 TMemberFunction

template<class TObject, class TMemberFunction>
static TReturn memberCaller(void *obj, TParameter... params) {
    // ...
}

无法用于捕获成员函数指针。 TMemberFunction 必须是一种类型,而您没有像这样使用它。

您可以按以下方式定义您的类:

template<class>
struct Functor;

template<class TReturn, class... TParameter>
struct Functor<TReturn(TParameter...)> {
    TReturn (*ptr)(void*, TParameter...);
    void     *object;

    template<class TObject, TReturn(TObject::*TMemberFunction)(TParameter...)>
    static TReturn memberCaller(void *obj, TParameter... params) {
        TObject *c = static_cast<TObject*>(obj);
        return (c->*TMemberFunction)(params...);
    }

    TReturn operator()(TParameter... params) {
        return ptr(object, params...);
    }
};

并且按照以下方式使用:

Functor<void(int)> f;
Test               t;

f.object = &t;
f.ptr    = &Functor<void(int)>::memberCaller<Test, &Test::func>;

f(100);

也就是说,您可以将成员函数作为memberCaller的模板参数使用,并在调用时擦除类型并在内部使用。

我还稍微更改了Functor的定义,使其可用于:

Functor<void(int)>

如果您打算将其与函数类型一起使用,则以下内容要更加明确:

Functor<void, int>

仅供参考。


wandbox上查看上述示例的运行情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接