Почему указатели на функции нарушают заменяемость, а std :: function — нет?

У нас есть обычная иерархия классов:

class B
{
public:
int x;
B() : x(0) {}
virtual ~B() {}
};

class D : public B
{
public:
int y;
D() : y(0) {}
};

И функция, которая принимает один аргумент — ссылку на объект базового класса.

void b_set(B& b)
{
b.x = 5;
}

Затем я хочу создать указатель на функцию типа void (D&) и хранить b_set в этом. Это должна быть допустимая операция, так как все объекты, законно переданные для вызова указателя функции, также должны иметь тип B. Однако это не разрешено.

typedef void (*fp_d_mutator)(D&);
void fp_test(D& obj)
{
fp_d_mutator fun = b_set; //invalid conversion from 'void (*)(B&)' to 'fp_d_mutator {aka void (*)(D&)}
fun(obj);
}

#include <functional>
typedef std::function<void (D&)> stdfun_d_mutator;
void stdfun_test(D& obj)
{
stdfun_d_mutator fun = b_set; //works
fun(obj);
}

Так…

  • Как это неверное преобразование?
  • Почему это недопустимое преобразование?
  • Что может сломаться, если это будет разрешено?
  • Как std :: function позволяет избежать проблемы?

3

Решение

Функция, которая принимает аргумент типа B& не является функцией, которая принимает аргумент типа D&, В то время как D& является конвертируемый в B&они не одного типа. Если бы вы могли хранить указатель на функцию, которая принимает B& как указатель на D&как компилятор узнает, когда нужно преобразовать аргумент? (Обратите внимание, что преобразование иногда требует настройки указателя)

Разница в std::function является то, что вызывающая подпись (здесь D&) является частью типа объекта функции, а также вызываемая подпись (здесь B&) является частью внутреннего хранилища. Поэтому, когда вы применяете функциональные объекты operator() код, который реализует operator()(D&) заботится о преобразовании.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]