声明一个模板函数,将模板类朋友的两个对象(仅)用于这两个特化

时间:2018-03-24 16:38:59

标签: c++ templates c++14 friend-function

我有一个模板类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>);
};

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

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

2 个答案:

答案 0 :(得分:1)

我提供解决方案。该功能不再是朋友功能。

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

答案 1 :(得分:0)

不,你不能这样做。

17.5.4朋友[temp.friend]

  

类或类模板的朋友可以是函数模板或类模板,函数模板或类模板的特化,或非模板函数或类。

在这六个选项中,您可能会对功能模板感兴趣。

所以你可以通过三种方式与运营商建立联系

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也不会有两个原因:第一,你需要在某处定义这个重载,第二,如果你定义了这样的重载,它将不适用于第二个参数(#2)和第一个参数( #3)。