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?
Templates are a feature of the C++ programming language that allows functions and classes to operate with generic types. This allows a function or class to work on many different data types without being rewritten for each one.
Explanation: Template function helps in writing functions that work with different types of parameters which is what polymorphism means i.e. using same function prototype to perform the same operations on different types of parameters.
A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type.
In template definitions, typename provides a hint to the compiler that an unknown identifier is a type. In template parameter lists, it's used to specify a type parameter.
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 function operator <<
.
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
friend std::ostream & operator<< <T>(std::ostream & output,
const DeviceType<T> & deviceType );
(note the explicit T
in <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
friend std::ostream & operator<<(std::ostream & output,
const DeviceType<T> & deviceType );
(i.e. no <>
at all), it would befriend an ordinary (non-template) function operator <<
, 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
void foo(int);
template <typename T> void foo(T);
int main() {
foo(42); // calls non-template function
foo<int>(42); // calls template function, explicit template argument given
foo<>(42); // calls template function, template argument deduced by compiler
}
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.
The compiler checks for <
after operator<<
if it's a friend function of a template class. It's considered as the template argument list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With