假设您的类层次结构稍微复杂一些:
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
你可以使用以下函数:
void takeA(A* ptr)
{
ptr->a = 1;
}
void takeB(B* ptr)
{
ptr->b = 2;
}
因此,我们可以说takeA
可用于任何派生自A
类(或A
本身)的实例,并且takeB
可用于任何B
类的实例:
takeA(new A);
takeA(new B);
takeA(new C);
takeB(new B);
现在,
std::function
是什么呢?它是一个可调用对象的包装器。它并不太关心存储函数对象的签名,只要该对象可以使用其
std::function
包装器的参数进行调用即可。请注意保留HTML标签。
std::function<void(A*)> a; // can store anything that is callable with A*
std::function<void(B*)> b; // can store anything that is callable with B*
你想做的是将
std::function<void(B*)>
转换为
std::function<void(A*)>
。换句话说,你想要存储可调用对象,该对象接受
B*
,并将其放入函数接受
A*
的包装类中。是否存在从
A*
到
B*
的隐式转换?答案是否定的。
也就是说,可以使用指向类
C
实例的指针调用
std::function<void(A*)>
。
std::function<void(A*)> a = &takeA;
a(new C); // valid! C* is forwarded to takeA, takeA is callable with C*
如果
std::function<void(A*)>
可以“包装”仅采用
B*
的可调用对象实例,您希望它如何与
C*
一起使用?
std::function<void(B*)> b = &takeB;
std::function<void(A*)> a = b;
a(new C); // ooops, takeB tries to access ptr->b field, that C class doesn't have!
幸运的是,上面的代码无法编译。
然而,将其相反地做是可以的:
std::function<void(A*)> a = &takeA;
std::function<void(B*)> b = a;
b(new B); // ok, interface is narrowed to B*, but takeA is still callable with B*
std::function
支持这样的 转换。但是在另一方面,你可以将std::function<void(A*)>
转换为std::function<void(B*)>
,因为作用于A*
的函数在接收到B*
实例时也可以执行相同的操作,但反过来则不行。 - Piotr Skotnickistd::function
作为回调而非接受一个Functor
作为模板参数。除非有充分的理由需要这样做,否则请不要这样做。 - pmrstd::function
?如果它向其中传递了一个指向class C:public A{}
的指针,那么thisIsAGivenFunction
会做什么?请回答这两个问题,它们都不是修辞问题。 - Yakk - Adam Nevraumont