user1965150
user1965150

Reputation:

dynamic cast a reference and auto

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

Answers (2)

Columbo
Columbo

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 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.

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

Bill Lynch
Bill Lynch

Reputation: 81926

You're getting Derived from auto. Use this instead:

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

Upvotes: 6

Related Questions