There is a code like this.
const std::string DeviceTypeStrings[] ={ "A", "B", "C", "D", "E" };
enum DeviceTypes { A = 0, B, C, D, E };
template <DeviceTypes T> class DeviceType;
template <DeviceTypes T> std::ostream& operator<< (std::ostream& output, const DeviceType<T>& dev);
template <DeviceTypes T> class DeviceType {
public:
static const int value = T;
static const std::string string;
friend std::ostream & operator<< <>(std::ostream & output, const DeviceType<T> & deviceType );
};
template <DeviceTypes T> const std::string DeviceType<T>::string = DeviceTypeStrings[T];
template <DeviceTypes T> std::ostream & operator<< (std::ostream & output, const DeviceType<T> & deviceType ){
if ( DeviceType<T>::string.find(' ') != std::string::npos ){
return output << "\"" << DeviceType<T>::string << "\"";
} else {
return output << DeviceType<T>::string;
}
}
int main () {
DeviceType<A> myType;
std::cout << myType << std::endl;
return 0;
}
Note there is a “<>” after the operator<< inside class DeviceType, what does “<>” mean? If you could, why does it has to be there?
It simply means that the friend declaration refers to a particular specialization of function template
operator <<(declared previously), not to some yet undeclared ordinary non-template functionoperator <<.Which specialization this friend declaration refers to is determined by the argument deduction mechanism, i.e. the actual template arguments are implicitly derived from the parameter types used in friend declaration. For this reason there’s no need to specify template arguments in
<>explicitly, but an empty pair of<>is still required.In other words, the author of the code could’ve stated explicitly
(note the explicit
Tin<T>). However, since the compiler can figure it out by itself (derive it from the type of the second argument), it is perefectly possible to put just an empty pair of<>there.Now, if the code just said
(i.e. no
<>at all), it would befriend an ordinary (non-template) functionoperator <<, which is not what the author wanted.Overload resolution feature that works in this friend declaration can be illustrated without any friend declarations by the following simple example
When you want to tell the compiler that you specifically want to refer to a template version of the function, you have to include triangular brackets into the reference, even if there’s nothing between them.