C++ 声明一个模板函数,将模板类的两个对象(仅)转换为这两个专门化

C++ 声明一个模板函数,将模板类的两个对象(仅)转换为这两个专门化,c++,templates,c++14,friend-function,C++,Templates,C++14,Friend Function,我有一个模板类Test(用一个整数作为模板参数)和一个模板函数(在本例中是操作符*),它接受两个Test类的对象,它们可能有不同的模板参数。函数需要与它的两个参数都是朋友。以下是一个最低限度的工作示例: #include <type_traits> template <int N> class Test; template <int N1, int N2> Test<N1+N2> operator* (Test<N1>, Test&

我有一个模板类
Test
(用一个整数作为模板参数)和一个模板函数(在本例中是
操作符*
),它接受两个
Test
类的对象,它们可能有不同的模板参数。函数需要与它的两个参数都是朋友。以下是一个最低限度的工作示例:

#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;
}
但是由于不明确的重载而遇到了g++错误。我还尝试:

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>);
};
模板
课堂测试{
双val;
公众:
测试(双x):val{x}{}
模板
朋友测试操作员*(测试,测试);
};
但是朋友声明不允许使用默认模板参数

我更喜欢C++14的解决方案,但也可以接受C++17的解决方案

更新:根据S.M.的回答,我建议对那些有类似问题的人采取以下解决方案

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;
}
模板
课堂测试{
双val;
公众:
测试(双x):val{x}{}
模板
测试操作员*(测试y){
返回测试{val*y.val};
}
模板
朋友类测验;
};
int main(int argc,char*argv[]){
测试a{4},c{7.9};
试验b{3.5};
a*b;
a*c;
返回0;
}
不,你不能这样做

17.5.4朋友[临时朋友]

类或类模板的朋友可以是函数模板或类模板、函数模板或类模板的专门化或非模板函数或类

在这6个选项中,您可能对函数模板感兴趣

所以你可以通过三种方式与接线员成为朋友

template <int N1, int N2>
friend Test<N1+N2> operator* (Test<N1>, Test<N2>); #1

template <int N2>
friend Test<N + N2> operator* (Test<N>, Test<N2>); #2

template <int N1>
friend Test<N1 + N> operator* (Test<N1>, Test<N>); #3
模板
朋友测试操作员*(测试,测试)#1.
模板
朋友测试操作员*(测试,测试)#2.
模板
朋友测试操作员*(测试,测试)#3.

选项#1您已经尝试过,但效果不如您所愿。选项#2和#3也不起作用,原因有二:首先,您需要在某处定义此重载,其次,如果您定义这样的重载,它将不适用于第二个参数(#2)和第一个参数(#3)。

我提供以下解决方案。该函数不再是友元函数

#include <type_traits>

template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}

  template <int N2>
  Test<N+N2> mul(const Test<N2> &y) const {
    return Test<N+N2>{val * y.val};
  }

  template <int N2>
  friend class Test;
};

template <int N1, int N2>
Test<N1+N2> operator* (const Test<N1> &x, const Test<N2> &y) {
  return Test<N1+N2>{x.template mul<N2>(y)};
}

int main (int argc, char* argv[]) {
  Test<1> a{4.}, c{7.9};
  Test<2> b{3.5};
  a*b;
  a*c;
  return 0;
}

这是一个奇怪的要求。那么,您希望那些不满足条件但无法访问私有数据的函数存在吗?一个合理的解决办法就是首先禁用它们。我无法理解这个要求。如果未调用
操作符*
,您希望它不是朋友吗?我不介意。删除的运算符声明在一方面,全局声明在另一方面。编译器无法选择使用哪一个。为什么
操作符*
首先要修改
测试的私有值?您为什么需要对此进行保护?@liliscent若要了解为什么需要此要求,请参阅此处方法1的问题@S.M。请参阅上面的注释#2和#3不要声明专门化。它们为每个可能的
N
声明了不同的重载,您可能需要以某种方式定义所有重载。@Ascheppler Yeh,您是对的,这些都是重载。谢谢非常感谢你。您能否提供一份参考资料,解释
x.template mul(y)
template
关键字的用法。如果我们将测试的所有专业化都交给了对方(这是合理的),我们也可以将乘法运算符定义为成员而不是非成员,对吗?是的,我们可以将运算符定义为成员函数。我没有像你回答的那样成为议员。查看我的更新。有关使用
模板
关键字的问题的答案请查看此处
#include <type_traits>

template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}

  template <int N2>
  Test<N+N2> mul(const Test<N2> &y) const {
    return Test<N+N2>{val * y.val};
  }

  template <int N2>
  friend class Test;
};

template <int N1, int N2>
Test<N1+N2> operator* (const Test<N1> &x, const Test<N2> &y) {
  return Test<N1+N2>{x.template mul<N2>(y)};
}

int main (int argc, char* argv[]) {
  Test<1> a{4.}, c{7.9};
  Test<2> b{3.5};
  a*b;
  a*c;
  return 0;
}
#include <type_traits>

template <int N>
class Test {
  double val;
public:
  Test (double x) : val{x} {}

  template <int N2>
  Test<N+N2> operator *(const Test<N2> &y) const {
    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;
}