7

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?

Negative Zero
  • 1,224
  • 3
  • 10
  • 19

3 Answers3

6

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
3

The compiler checks for < after operator<< if it's a friend function of a template class. It's considered as the template argument list.

Rapptz
  • 20,807
  • 5
  • 72
  • 86
  • I'm pretty sure `friend` is unrelated here. Actually, I can't replicate the problem without `friend`, so maybe it is. I'm glad I didn't downvote. – Mooing Duck Aug 24 '12 at 22:32
  • 1
    Can you educate me a little more on why is this necessary? – Negative Zero Aug 24 '12 at 22:32
  • @NegativeZero It would specify the type such as , , etc when you specify the type of outputting you want such as operator<< (std << cout, className). I don't think it's too overly important. I tried to elaborate more and I came across a few links that are better at explaining it than me while looking for clearer info. http://stackoverflow.com/a/1789637/1381108 – Rapptz Aug 24 '12 at 22:35
0

It is same like at this link. See the "Template specialization" chapter.

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

It's just how you refer to already defined template object (or function).

klm123
  • 12,105
  • 14
  • 57
  • 95