将函数指针传递到模板

Pass function pointer to template

本文关键字:函数 指针      更新时间:2023-10-16

我确实遇到过类似的情况:

#include <iostream>
template<class B>
class A
{
public:
    A<B>(const B& b) : m_b(b) {}
    void foo()
    {
        m_b(*this);
    }
private:
    B m_b;
};
class B
{
public:
    template<class C>
    void operator()(const C& c)
    {
        std::cout << "Bar!n";
    }
};

int main()
{
    B b;        
    A<B> a(b);
    a.foo();
    return 0;
}

然后我决定使用函数指针而不是函数对象b,也就是说,我想做这样的事情:

#include <iostream>
template<class B>
class A
{
public:
    A<B>(const B& b) : m_b(b) {}
    void foo()
    {
        m_b(*this);
    }
private:
    B m_b;
};
template<class C>
void bar(const C& c)
{
std::cout << "Bar!n";
}
int main()
{
    typedef void (*barPointer)(const A<barPointer>& a); // <--       
    A<barPointer> a(&bar);
    a.foo();
    return 0;
}

这显然不会编译(注意<--处的循环性)。我的问题是:人们会怎么做?

我认为要问的关键问题是您的barPointer类型是什么?它是一个逐点函数,但当您试图定义它时,您已经创建了一个无限递归的定义。为了结束递归,你必须考虑这个指针类型的"根"或"基本情况"是什么。由于你知道要传递给函数的A实例的类型,那么你实际上是在寻找一个"占位符"类型,它可以在没有循环的情况下实例化模板。这可能是一个非常"通用"的函数指针类型,如void(*)(void*),也可能是更具体的类型,但在任何一种情况下,我认为它都需要是一个不包括A定义的函数指针,但可以传递一个A<>实例作为其参数。最通用的形式是void(*)(void*),但为了更大的类型安全性,您也可以定义某种类型的多态基类。

例如,这里有一个最通用的例子:

typedef void (*generic_t)(void*);
template<typename T>
struct A
{
        A(const T& t): func_ptr(t) {}
        void foo() { func_ptr(this); }
        T func_ptr;
};
void func(void* arg)
{
        const A<generic_t>* a = reinterpret_cast<const A<generic_t>*>(arg);
}
int main()
{
        A<generic_t> a(&func);
        a.foo();
        return 0;
}

尽管这看起来很危险,但如果考虑到在basePointer示例中您已经知道要传递给basePointer函数指针的对象类型,那就不是真的了。如果您想要更多的类型安全性来防止无意的错误,那么您可以始终创建A继承自的某种类型的抽象基类。我说"抽象基类"是因为这将允许您使用传递给函数的指针,而无需显式转换为它的派生类型。然后,您的"通用占位符"函数ptr类型可能类似于void(*)(const Base&),而不是非类型安全的void(*)(void*)