声明一个模板函数,将模板类友元的两个对象(仅)带到这两个专用化



我有一个模板类Test(用整数作为模板参数(和一个模板函数(在本例中operator*(,它接受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;
}

这有效,但该功能是Test每个专业的朋友。我想让它只和Test<N1>Test<N2>成为朋友。

我尝试这样声明它:

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

但是遇到了不明确的重载的 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>);
};

但 FRIEND 声明不允许使用默认模板参数。

我更喜欢 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;
}

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

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

作为会员operator *

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

不,你不能这样做。

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 也不起作用,原因有两个:首先,您需要在某处定义此重载,其次,如果您定义这样的重载,则不适用于第二个参数 和第一个参数 。

最新更新