I have a template class Test (with an integer as template argument) and a template function (in this case operator*) that takes two objects of Test class with possibly different template arguments. The function needs to be friend to both its arguments. Here is a minimally working example:
#include <type_traits>
template <int N>
class Test;
template <int N1, int N2>
Test<N1+N2> operator* (Test<N1>, Test<N2>);
template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}
  template <int N1, int N2>
  friend Test<N1+N2> operator* (Test<N1>, Test<N2>);
};
template <int N1, int N2>
Test<N1+N2> operator* (Test<N1> x, Test<N2> y) {
  return Test<N1+N2> {x.val*y.val};
}
int main (int argc, char* argv[]) {
  Test<1> a{4.}, c{7.9};
  Test<2> b{3.5};
  a*b;
  a*c;
  return 0;
}
This works, but the function is friend to every specializations of Test. I want to make it to be friend only with Test<N1> and Test<N2>.
I tried declaring it like this:
template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}
  template <int N1, int N2>
  friend std::enable_if_t<N1==N||N2==N,Test<N1+N2>> operator* (Test<N1>, Test<N2>);
};
but encountered g++ errors for ambiguous overloads. I also tried:
template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}
  template <int N1, int N2, typename = std::enable_if_t<N1==N||N2==N>>
  friend Test<N1+N2> operator* (Test<N1>, Test<N2>);
};
but default template arguments are not allowed for friend declarations.
I prefer a solution in C++14 but solutions in C++17 would also be acceptable.
Update: Following the answer of S.M. I suggest the following solution to those with similar problems
template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}
  template <int N2>
  Test<N+N2> operator* (Test<N2> y) {
    return Test<N+N2> {val*y.val};
  }
  template <int N2>
  friend class Test;
};
int main (int argc, char* argv[]) {
  Test<1> a{4.}, c{7.9};
  Test<2> b{3.5};
  a*b;
  a*c;
  return 0;
}