The fact that you name your template parameter
ostream
and instantiate it withstd::ostream&
is confusing.There is a minor bug in the demangling (it should have put a space to break the group of
&
as its meaning is& &&
and not&& &
), but the presence of the consecutive&
themselves is not a problem: another way to demangle the name would have beenvoid bar<$T=std::ostream$&>($T$&&)
, i.e. the mangled name contains backreference to the parameters and not an expansion of the type itself.Why? In general, the mangled names of instantiations have to represent the precise instantiated template and its paramaters (as opposed to use the signature resulting from things like the collapsing rule or expanding references to traits) as instatiation of two different function template of the same name resulting in the same signature can validly coesist in a program (I don't think they can in a compilation unit, but name look up and overload resolution is so complex in C++ that I may be mistaken) and using a simplified signature would merge them inadequately. And example with traits, I can't currently think of one with the reference collapsing rules(*), the two function templates which follow may be overloaded in a program (even in the same CU)
template <typename T> struct Traits{}; template <typename T> void f(typename Traits<T>::T1) { return; } template <typename T> void f(typename Traits<T>::T2) { return; }
But if you have the following specialization of Traits
template <> struct Traits<int> { typedef int T1; typedef int T2; };
you can't use
f<int>(42)
at a place where both are visible as there is an ambiguity, but by making them selectively visible you could use one in a CU and the other in another CU, so the mangling has to be able to make a difference.
(*) It is possible that there is none, I don't remember having seen one mentionned and as soon as the mechanism has to be in place (another reason is to limit the size of mangled names), it's safer and also probably easier ato continue to use it for everything.