質問

We have an usual class hierarchy:

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

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

And a function that takes one argument - reference to a base class object.

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

Then, I want to create function pointer of type void (D&) and store b_set in it. This should be valid operation, as all objects legally passed to function pointer call must be also of type B. Yet it isn't allowed.

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);
}

So...

  • How is that invalid conversion?
  • Why is that invalid conversion?
  • What could break if this was allowed?
  • How std::function avoids the problem in the first place?
役に立ちましたか?

解決

A function that takes an argument of type B& is not a function that takes an argument of type D&. While D& is convertible to B&, they are not the same type. If you could store a pointer to a function that takes B& as a pointer to D&, how would the compiler know when to convert the argument? (Note that the conversion sometimes requires adjusting a pointer)

The difference in std::function is that the calling signature (here D&) is part of the function object's type, and the called signature (here B&) is part of the internal storage. So when you apply the function objects' operator() the code that implements operator()(D&) takes care of the conversion.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top