我确实有类似的情况:
#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;
}
这显然不能编译(注意&lt; - 的圆形度)。我的问题是:怎么会这样呢?
答案 0 :(得分:0)
我认为要问的关键问题是你的barPointer
类型是什么?它是一个指向函数的指针,但是当你试图定义它时,你已经创建了一个无限递归的定义。要结束递归,您必须考虑此指针类型的“根”或“基本情况”。既然您知道A
实例的类型,那么您将传递给您的函数,那么您确实在寻找一种“占位符”类型,它允许在没有循环的情况下实例化模板。这可能是一个非常“通用”的函数指针类型,如void(*)(void*)
,或者它可能更具体,但在任何一种情况下,我认为它需要是一个函数指针类型,不包括{的定义{1}},但可以传递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
继承的抽象基类。我说“抽象基类”因为这将允许您使用传递给函数的指针而不显式转换为它的派生类型。那么你的“通用占位符”函数-ptr类型可能类似于A
而不是非类型安全的void(*)(const Base&)
。