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

これは単に、friend宣言が、まだ宣言されていない通常の非テンプレート関数ではなく、 関数テンプレート の特定の特殊化(以前に宣言された)を参照していることを意味します。operator <<operator <<

このフレンド宣言が参照する特殊化は、引数推定メカニズムによって決定されます。つまり、実際のテンプレート引数は、フレンド宣言で使用されるパラメータータイプから暗黙的に導出されます。このため、テンプレート引数を<>明示的に指定する必要はありませんが、空のペアが<>必要です。

言い換えれば、コードの作成者は明示的に述べることができたはずです

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

T(の明示的なことに注意してください<T>)。ただし、コンパイラはそれを自分で理解できるため(2番目の引数の型から導出)、空のペアだけをそこに置くことは完全に可能<>です。

さて、コードがちょうど言った場合

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 に答える