动态转换参考和自动
dynamic cast a reference and auto
我在使用 auto 和 dynamic_cast 时遇到了一个非常奇怪的行为。
这是我的 class 层次结构:
class BaseInterface {
public:
virtual void someMethod()=0;
};
class Derived:public BaseInterface {
public:
virtual void someMethod1()=0;
void someMethod()override;
};
当然还有一些 class 实现所有派生方法。
然后是第三个 class 看起来像这样:
class ThirdClass {
public:
void demoMethod(BaseInterface&);
void anotherMethod(Derived&);
};
void ThirdClass::demoMethod(BaseInterface& obj) {
auto buffer=dynamic_cast<Derived&>(obj);
anotherMethod(buffer);
}
当我用 gcc 编译它时,出现 "cannot allocate an object of abstract type" 错误。而当我更换
auto buffer=...
和
Derived& buffer=...
编译一切正常。为什么会这样?是 auto 没有推导出正确的类型还是什么?
我还发现了一个仍然使用自动的肮脏技巧:
void ThirdClass::demoMethod(Base& obj) {
auto buffer=dynamic_cast<Derived*>(&obj);
anotherMethod(*buffer);
}
您正在从 auto
获得 Derived
。改用这个:
auto & buffer = dynamic_cast<Derived&>(obj);
§7.1.6.4/7:
When a variable declared using a placeholder type is initialized […]
the deduced return type or variable type is determined from the type
of its initializer. […] let T
be the declared type of the variable
or return type of the function. If the placeholder is the auto
type-specifier, the deduced type is determined using the rules for
template argument deduction. […] obtain P
from T
by replacing the
occurrences of auto
with either a new invented type template
parameter U
[…]. Deduce a value for U
using the rules of template
argument deduction from a function call (14.8.2.1), where P
is a
function template parameter type and the corresponding argument is the
initializer.
因此,为了熟悉该过程,请看一下用于推导 buffer
类型的实际规则:如果更改
会发生什么
template <typename U>
void f( U );
到
void f( Derived& );
当使用 Derived
类型的左值调用 f
时?显然,对于函数模板,U
将被推导为 Derived
,从而导致推导失败。
这直接对应于您示例中占位符类型的推导 - auto
将被 Derived
替换,并且失败,因为 Derived
是抽象的。
一般来说,如果你写
auto obj = …;
obj
永远不会是引用,就像调用上面的函数模板时U
永远不会被推导为引用类型一样
而是使用 auto&
:
auto& buffer = dynamic_cast<Derived&>(obj);
现在,P
是 U&
:
template <typename U>
void f(U&);
U
当然仍然推导为 Derived
,但是 P
的类型——实际上是 buffer
的类型——是 Derived&
.
我在使用 auto 和 dynamic_cast 时遇到了一个非常奇怪的行为。 这是我的 class 层次结构:
class BaseInterface {
public:
virtual void someMethod()=0;
};
class Derived:public BaseInterface {
public:
virtual void someMethod1()=0;
void someMethod()override;
};
当然还有一些 class 实现所有派生方法。
然后是第三个 class 看起来像这样:
class ThirdClass {
public:
void demoMethod(BaseInterface&);
void anotherMethod(Derived&);
};
void ThirdClass::demoMethod(BaseInterface& obj) {
auto buffer=dynamic_cast<Derived&>(obj);
anotherMethod(buffer);
}
当我用 gcc 编译它时,出现 "cannot allocate an object of abstract type" 错误。而当我更换
auto buffer=...
和
Derived& buffer=...
编译一切正常。为什么会这样?是 auto 没有推导出正确的类型还是什么?
我还发现了一个仍然使用自动的肮脏技巧:
void ThirdClass::demoMethod(Base& obj) {
auto buffer=dynamic_cast<Derived*>(&obj);
anotherMethod(*buffer);
}
您正在从 auto
获得 Derived
。改用这个:
auto & buffer = dynamic_cast<Derived&>(obj);
§7.1.6.4/7:
When a variable declared using a placeholder type is initialized […] the deduced return type or variable type is determined from the type of its initializer. […] let
T
be the declared type of the variable or return type of the function. If the placeholder is theauto
type-specifier, the deduced type is determined using the rules for template argument deduction. […] obtainP
fromT
by replacing the occurrences ofauto
with either a new invented type template parameterU
[…]. Deduce a value forU
using the rules of template argument deduction from a function call (14.8.2.1), whereP
is a function template parameter type and the corresponding argument is the initializer.
因此,为了熟悉该过程,请看一下用于推导 buffer
类型的实际规则:如果更改
template <typename U>
void f( U );
到
void f( Derived& );
当使用 Derived
类型的左值调用 f
时?显然,对于函数模板,U
将被推导为 Derived
,从而导致推导失败。
这直接对应于您示例中占位符类型的推导 - auto
将被 Derived
替换,并且失败,因为 Derived
是抽象的。
一般来说,如果你写
auto obj = …;
obj
永远不会是引用,就像调用上面的函数模板时U
永远不会被推导为引用类型一样
而是使用 auto&
:
auto& buffer = dynamic_cast<Derived&>(obj);
现在,P
是 U&
:
template <typename U>
void f(U&);
U
当然仍然推导为 Derived
,但是 P
的类型——实际上是 buffer
的类型——是 Derived&
.