【问题标题】:dynamic cast a reference and auto动态投射参考和自动
【发布时间】:2015-07-25 15:59:03
【问题描述】:

我在使用 auto 和 dynamic_cast 时遇到了一个非常奇怪的行为。 这是我的类层次结构:

class BaseInterface {
public:
    virtual void someMethod()=0;
};

class Derived:public BaseInterface {
public:
    virtual void someMethod1()=0;
    void someMethod()override;
};

当然还有一些类实现了所有派生方法。

然后是第三个类,如下所示:

class ThirdClass {
public:
    void demoMethod(BaseInterface&);
    void anotherMethod(Derived&);
};

void ThirdClass::demoMethod(BaseInterface& obj) {
    auto buffer=dynamic_cast<Derived&>(obj);
    anotherMethod(buffer);
}

当我用 gcc 编译它时,我得到一个“无法分配抽象类型的对象”错误。而当我更换时

auto buffer=...

Derived& buffer=...

一切编译正常。为什么会这样?是 auto 没有推断出正确的类型吗?

我还发现了一个仍然使用自动的肮脏技巧:

void ThirdClass::demoMethod(Base& obj) {
    auto buffer=dynamic_cast<Derived*>(&obj);
    anotherMethod(*buffer);
}

【问题讨论】:

  • 我猜auto 推断出Derived buffer 的类型,而不是Derived&amp; buffer
  • 您使用的是什么版本的 g++?可以很好地编译您的代码[在修复琐碎的拼写错误之后,例如 demoMethod 上没有返回类型,derived 上没有继承] - clang++ 3.7(大约两周前)和 g++ 4.9.2。
  • @MatsPetersson:如果丢失的返回类型已修复,则无论使用何种编译器 ideone,它都会以报告的方式失败:ideone.com/UEtfui
  • @BillLynch:当代码在您尝试它和下一个尝试它的人之间发生变化时总是很好...... ;)
  • @BillLynch:仅供参考,将鼠标悬停在“C++14”上以查看它使用的编译器(作为记录,在撰写本文时它是 GCC 4.9.2)。

标签: c++ c++11 reference auto dynamic-cast


【解决方案1】:

您从auto 获得Derived。改用这个:

auto & buffer = dynamic_cast<Derived&>(obj);

【讨论】:

    【解决方案2】:

    §7.1.6.4/7:

    当使用占位符类型声明的变量被初始化时 […] 推导的返回类型或变量类型由类型确定 其初始化程序。 […] 让T 成为变量的声明类型 或函数的返回类型。 如果占位符是auto 类型说明符,推导的类型是使用规则确定的 模板参数推导。 […] 通过替换 auto 出现在新发明的类型模板中 参数U[…]。 使用模板规则推导出U的值 从函数调用 (14.8.2.1) 中推导参数,其中 P 是 函数模板参数类型和对应的实参是 初始化器。

    所以,为了熟悉这个过程,看一下用于推断buffer类型的实际规则:如果你改变了会发生什么

    template <typename U>
    void f( U );
    

    void f( Derived& );
    

    当使用Derived 类型的左值调用f 时?显然,对于函数模板,U 将推演为Derived,则推演失败。
    这直接对应于您示例中对占位符类型的推导 - auto 将被 Derived 替换,并且失败,因为 Derived 是抽象的。

    一般来说,如果你写

    auto obj = …;
    

    obj 永远不会是引用,就像调用上述函数模板时U 永远不会被推断为引用类型。


    改为使用auto&amp;:

    auto& buffer = dynamic_cast<Derived&>(obj);
    

    现在,PU&amp;

    template <typename U>
    void f(U&);
    

    当然,U 仍被推断为Derived,但P 的类型——实际上是buffer 的类型——是Derived&amp;

    【讨论】:

    • @LightnessRacesinOrbit 好吧,我认为提问者用于模板参数推导:)
    • @Columbo 老实说我不是。我像 3 个月前一样刚开始使用 c++,还没有偶然发现模板。
    • @SuppenGeist 在这种情况下,没关系。也许其他人会发现这个答案很有用。
    猜你喜欢
    • 2012-05-14
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 2014-11-16
    • 2019-09-01
    • 1970-01-01
    相关资源
    最近更新 更多