有这样的代码.
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;
}
Run Code Online (Sandbox Code Playgroud)
注意运算符<<内部类DeviceType之后有一个"<>","<>"是什么意思?如果可以,为什么必须在那里?
它只是意味着友元声明引用了函数模板 的特定特性operator <<(先前声明过),而不是某些尚未声明的普通非模板函数 operator <<.
这个朋友声明引用的哪个特化是由参数推导机制决定的,即实际模板参数是从友元声明中使用的参数类型隐式派生的.因此,无需<>明确指定模板参数,但<>仍需要一对空参数.
换句话说,代码的作者可以明确说明
friend std::ostream & operator<< <T>(std::ostream & output,
const DeviceType<T> & deviceType );
Run Code Online (Sandbox Code Playgroud)
(注意明确T的<T>).但是,由于编译器可以自己解决它(从第二个参数的类型派生出来),所以完全可以在那里放一个空对<>.
现在,如果代码只是说
friend std::ostream & operator<<(std::ostream & output,
const DeviceType<T> & deviceType );
Run Code Online (Sandbox Code Playgroud)
(即根本没有<>),它将是一个普通的(非模板)函数operator <<,这不是作者想要的.
通过以下简单示例,可以在没有任何好友声明的情况下说明在此好友声明中起作用的过载分辨率功能
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
}
Run Code Online (Sandbox Code Playgroud)
当您想告诉编译器您特别想要引用该函数的模板版本时,您必须在引用中包含三角括号,即使它们之间没有任何内容.