Β§7.1.6.4 / 7:
When a variable declared using the placeholder type, the output type [...] returned is initialized or the type of the variable is determined by the type of its initializer. [...] let T is the declared type of the variable or the return type of the function. If the placeholder is auto type-specifier, the type being deduced is determined using the rules to output the template argument. [...] get P from T by replacing the occurrences of auto or using the new template type parameter U [...]. Derive a value for U using the template rules to derive an argument from a function call (14.8.2.1), where P is the type of the function template parameter, and the corresponding argument is the initializer.
So, to familiarize yourself with the process, take a look at the actual rule used to output the buffer type: what happens if you change
template <typename U> void f( U );
to
void f( Derived& );
when calling f with an lvalue of type Derived ? Obviously, for the function template, U will be displayed as Derived , which will then fail.
This directly matches the placeholder type deduction in your example - auto will be replaced with Derived , and this will not work, since Derived is abstract.
Generally speaking, if you write
auto obj = β¦;
obj will never be a reference , since U will never be inferred as a reference type when calling the above function template.
Use auto& instead:
auto& buffer = dynamic_cast<Derived&>(obj);
Now P is U& :
template <typename U> void f(U&);
U , of course, is still output as Derived , but the type P - which is actually the buffer type - Derived& .
source share