Reputation:
I've encountered a pretty weird behavior when using auto and dynamic_cast. This is the class hierachy i have:
class BaseInterface {
public:
virtual void someMethod()=0;
};
class Derived:public BaseInterface {
public:
virtual void someMethod1()=0;
void someMethod()override;
};
And of course there are some classes that implement all derived methods.
Then there is a third class which looks like this:
class ThirdClass {
public:
void demoMethod(BaseInterface&);
void anotherMethod(Derived&);
};
void ThirdClass::demoMethod(BaseInterface& obj) {
auto buffer=dynamic_cast<Derived&>(obj);
anotherMethod(buffer);
}
When i compile this with gcc i get an "cannot allocate an object of abstract type" error. Whereas when i replace
auto buffer=...
with
Derived& buffer=...
everything compiles fine. Why is that the case? Is auto not deducing the right type or something?
Also i found a dirty trick to still use auto:
void ThirdClass::demoMethod(Base& obj) {
auto buffer=dynamic_cast<Derived*>(&obj);
anotherMethod(*buffer);
}
Upvotes: 6
Views: 2641
Reputation: 60979
§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.
So, in order to familiarize yourself with the process, take a look at the actual rule used for deducing the type of buffer
: What happens if you change
template <typename U>
void f( U );
to
void f( Derived& );
when calling f
with an lvalue of type Derived
? Clearly, for the function template, U
will be deduced as Derived
, which then yields a deduction failure.
This directly corresponds to the deduction of the placeholder type in your example - auto
will be replaced by Derived
, and that fails, as Derived
is abstract.
Generally speaking, if you write
auto obj = …;
obj
will never be a reference, just as U
will never be deduced as a reference type when calling the above function template.
Instead, use auto&
:
auto& buffer = dynamic_cast<Derived&>(obj);
Now, P
is U&
:
template <typename U>
void f(U&);
U
is, of course, still deduced as Derived
, but the type of P
- which is effectively the type of buffer
- is Derived&
.
Upvotes: 4
Reputation: 81926
You're getting Derived
from auto
. Use this instead:
auto & buffer = dynamic_cast<Derived&>(obj);
Upvotes: 6