7

有这样的代码。

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;    
}

注意类DeviceType里面的operator<<后面有个“<>”,“<>”是什么意思?如果可以,为什么它必须在那里?

4

3 回答 3

6

它只是意味着朋友声明是指函数模板 operator <<的特定特化(先前声明的),而不是一些尚未声明的普通非模板函数 operator <<

这个友元声明所指的特化是由参数推导机制决定的,即实际的模板参数是从友元声明中使用的参数类型隐式派生的。由于这个原因,不需要显式指定模板参数,但仍然需要<>一对空的。<>

换句话说,代码的作者本可以明确说明

friend std::ostream & operator<< <T>(std::ostream & output, 
                                     const DeviceType<T> & deviceType );

(注意 中的显式T<T>。但是,由于编译器可以自己计算出来(从第二个参数的类型派生出来),所以完全可以只放一个空的对<>

现在,如果代码刚刚说

friend std::ostream & operator<<(std::ostream & output, 
                                 const DeviceType<T> & deviceType );

(即根本没有<>),它会成为一个普通的(非模板)函数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
}

当您想告诉编译器您特别想引用函数的模板版本时,您必须在引用中包含三角括号,即使它们之间没有任何内容。

于 2012-08-24T22:47:09.250 回答
3

编译器检查<afteroperator<<是否是模板类的友元函数。它被认为是模板参数列表。

于 2012-08-24T22:12:26.617 回答
0

与此链接相同。请参阅“模板专业化”一章。

// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase () {return ++element;}
};

// class template specialization:
template <>
class mycontainer <char> {
    char element;
  public:
    mycontainer (char arg) {element=arg;}
    char uppercase ()
    {
      if ((element>='a')&&(element<='z'))
      element+='A'-'a';
      return element;
    }
};

int main () {
  mycontainer<int> myint (7);
  mycontainer<char> mychar ('j');
  cout << myint.increase() << endl;
  cout << mychar.uppercase() << endl;
  return 0;
}

这就是您引用已定义的模板对象(或函数)的方式。

于 2012-08-24T22:52:18.643 回答