Ответ 1
Предположим, что ваша иерархия классов немного больше:
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);
// takeB(new A); // error! can't convert from A* to B*
// takeB(new C); // error! can't convert from C* to B*
Теперь, что std::function
, это оболочка для вызываемых объектов. Его не волнует подпись подписи хранимого функционального объекта до тех пор, пока этот объект может быть вызван с параметрами его обертки std::function
:
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*
? Нет, нет.
То есть, можно также вызвать std::function<void(A*)>
с указателем на экземпляр класса C
:
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*