声明一个模板函数,将模板的两个对象 class 作为(仅)这两个特化的朋友
Declare a template function taking two objects of a template class friend to (only) those two specializations
我有一个模板 class Test
(以一个整数作为模板参数)和一个模板函数(在本例中为 operator*
),它采用 [=15= 的两个对象] class 可能有不同的模板参数。该函数需要对其两个参数都是友好的。这是一个最低限度的工作示例:
#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;
}
不,你不能这样做。
17.5.4 好友[temp.friend]
A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class.
在这 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 也不会工作,原因有两个:首先,您需要在某处定义此重载,其次,如果您定义这样的重载,它将不适用于第二个参数 (#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;
}
作为会员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;
}
我有一个模板 class Test
(以一个整数作为模板参数)和一个模板函数(在本例中为 operator*
),它采用 [=15= 的两个对象] class 可能有不同的模板参数。该函数需要对其两个参数都是友好的。这是一个最低限度的工作示例:
#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;
}
不,你不能这样做。
17.5.4 好友[temp.friend]
A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class.
在这 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 也不会工作,原因有两个:首先,您需要在某处定义此重载,其次,如果您定义这样的重载,它将不适用于第二个参数 (#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;
}
作为会员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;
}