0

When providing the operator<< for a specialization of a template class, clang likes the inline friend form:

#include <iostream>

template <typename A, typename... Bs>
struct Hello;

template <typename A>
struct Hello<A> {
  template <typename A2>
  friend std::ostream & operator<<(std::ostream & s, const Hello<A2> & h) {
    return s << "specialized\n";
  }
};

template <typename A, typename... Bs>
struct Hello {
  template <typename A2, typename... B2s>
  friend std::ostream & operator<<(std::ostream & s, const Hello<A2,B2s...> & h) {
    return s << "generic\n";
  }
};


int main()
{
  std::cout << Hello<int>() 
            << Hello<float>()
            << Hello<int,int>()
            << Hello<int,float>();
}

http://coliru.stacked-crooked.com/a/47743db96c0f3a02

However gcc fails with that, it prefers the non-inline version:

#include <iostream>

template <typename A, typename... Bs>
struct Hello;

template <typename A>
struct Hello<A> {
  template <typename A2>
  friend std::ostream & operator<<(std::ostream & s, const Hello<A2> & h);
};

template <typename A, typename... Bs>
struct Hello {
  template <typename A2, typename... B2s>
  friend std::ostream & operator<<(std::ostream & s, const Hello<A2,B2s...> & h);
};


template <typename A2>
std::ostream & operator<<(std::ostream & s, const Hello<A2> & h) {
  return s << "specialized\n";
}

template <typename A2, typename... B2s>
std::ostream & operator<<(std::ostream & s, const Hello<A2,B2s...> & h) {
  return s << "generic\n";
}


int main()
{
  std::cout << Hello<int>() 
            << Hello<float>() 
            << Hello<int,int>() 
            << Hello<int,float>();
}

http://coliru.stacked-crooked.com/a/45328f7bbdb36598

Which, in turn, is not accepted by clang.

So my questions are:

  1. Are both the forms standard C++?
  2. Is there a form that is accepted by both the compilers?
DarioP
  • 5,377
  • 1
  • 33
  • 52
  • 1
    Somehow related: http://stackoverflow.com/questions/1297609/overloading-friend-operator-for-template-class – DarioP May 12 '15 at 13:15

1 Answers1

2

You don't need a template friend.

template <typename A, typename... Bs>
struct Hello {
  friend std::ostream & operator<<(std::ostream & s, const Hello<A,Bs...> & h) {
    return s << "generic\n";
  }
};

template <typename A>
struct Hello<A> {
  friend std::ostream & operator<<(std::ostream & s, const Hello<A> & h) {
    return s << "specialized\n";
  }
};

http://coliru.stacked-crooked.com/a/22c439bc920f948c

Oktalist
  • 14,336
  • 3
  • 43
  • 63