std :: bind会舍弃C ++ 11中参数的类型信息吗? [英] Does std::bind discard type information of parameters in C++11?

查看:135
本文介绍了std :: bind会舍弃C ++ 11中参数的类型信息吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出现问题的地方

请考虑以下c ++代码:

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

在此示例中,我们有两个类AB. B继承自类A.这两个类都实现了一个简单的虚拟方法,该方法返回类型名称.

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.

还有一个简单的方法print,它接受对A实例的引用并打印类型.

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

State保存对A实例的引用.该类还有一个简单的方法,可以通过两种不同的方式调用print.

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.

奇怪的地方

处于状态的唯一方法首先直接调用print.因为我们在main方法中提供了B int的实例,所以输出如预期的那样是It's B.

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.

但是,对于第二个调用,我们使用std::bind将实例绑定到print的第一个参数.然后,我们调用没有任何参数的结果函数.

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.

但是,在这种情况下,输出为It's A.我应该像以前一样期望输出It's B,因为它仍然是相同的实例.

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.

如果我将参数声明为指针而不是引用,则std::bind会按预期工作.我还将一些日志记录到两个类的构造函数中,以验证是否没有意外创建实例.

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.

为什么会这样?在这种情况下,std::bind是否会丢弃某些类型信息?据我了解,这一定不会发生,因为方法调用应通过运行时的vtable查找进行管理.

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.

推荐答案

这只是对象切片.通过引用传递实例:

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

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

进一步解释一下:与大多数C ++标准库类型一样,bind表达式的结果类型拥有的所有绑定状态.这意味着您可以使用此值并自由传递它,然后将其存储并在不同的上下文中稍后再使用它,并且仍可以将其绑定状态准备就绪以进行操作.

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.

因此,在您的代码中,绑定对象是使用副本构造的.但是由于instance并不是一个完整的对象,所以您导致了切片的发生.

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.

相比之下,我的代码将std::reference_wrapper<A>复制到绑定对象中,这实际上是一个指针.它不拥有实例对象,因此只要绑定对象可以被调用,我就必须保持它处于活动状态,但这意味着绑定调用将以多态方式分派给整个对象.

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.

这篇关于std :: bind会舍弃C ++ 11中参数的类型信息吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆