Does std::bind discard type information of parameters in C++11?

半世苍凉 提交于 2019-12-04 03:52:02

问题


Case where the problem occours

Please consider the following c++ code:

#include <functional>
#include <iostream>
#include <string>

// Superclass
class A {
    public:
    virtual std::string get() const {
        return "A";
    }
};

// Subclass
class B : public A {
    public:
    virtual std::string get() const {
        return "B";
    }
};

// Simple function that prints the object type
void print(const A &instance) {
    std::cout << "It's " << instance.get() << std::endl;
}

// Class that holds a reference to an instance of A
class State {
    A &instance;
    public:
    State(A &instance) : instance(instance) { }
    void run() {

        // Invokes print on the instance directly
        print(instance);

        // Creates a new function by binding the instance
        // to the first parameter of the print function, 
        // then calls the function. 
        auto func = std::bind(&print, instance);    
        func();
    }    
};

int main() {
    B instance;
    State state(instance);

    state.run();
}

In this example, we have two classes A and B. B inherits from class A. Both classes implement a simple virtual method that returns the type name.

There is also a simple method, print, that accepts a reference to an instance of A and prints the type.

The class State holds a reference to an instance of A. The class also has a simple method that calls print by two different means.

Where it gets odd

The sole method in state first calls print directly. Since we supply an instance of B int the main method, the output is It's B, as expected.

For the second call, however, we bind the instance to the first parameter of print using std::bind. Then we call the resulting function without any arguments.

In this case, however, the output is It's A. I would have expected the output It's B, as before, since it is still the same instance.

If I declare the parameters as pointers instead of references, std::bind works as expected. I also placed some logging into the constructors of both classes to verify that no instances are created accidentally.

Why does this happen? Does std::bind discard some type information in this case? To my understanding, this must not happen since the method invocation should be managed by a vtable lookup via runtime.


回答1:


This is just object slicing. Pass the instance by reference:

auto func = std::bind(&print, std::ref(instance));
//                            ^^^^^^^^

To explain this a bit more: Like most C++ standard library types, the result type of a bind expression owns all its bound state. This means you can take this value and pass it around freely and store it and come back to it later in a different context, and you can still call it with all its bound state ready for action.

Therefore, in your code, the bind object was constructed with a copy of instance. But since instance wasn't a complete object, you caused slicing to happen.

By contrast, my code copies a std::reference_wrapper<A> into the bind object, and that's essentially a pointer. It doesn't own the instance object, so I need to keep it alive as long as the bind object may get called, but it means that the bound call is dispatched polymorphically to the complete object.



来源:https://stackoverflow.com/questions/34366167/does-stdbind-discard-type-information-of-parameters-in-c11

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!