C++ 类模板部分专用化,而不专用化所有成员函数

c++ class template partial specialization without specializing all member functions

本文关键字:专用 成员 函数 板部 C++      更新时间:2023-10-16

假设我有一个类X<'T,N'>,它定义了几个函数,我也希望类X<'T,3'>拥有它们,但也有一些额外的函数(一个现实生活中的例子是Vector<'T,N'>和Vector<'T,3'>将具有所有Vector<'T, N'>功能,但也可以实现3D空间中的旋转(

template <class T, size_t N>
class X {
public:
void a();
X<T, N> b(X<T, N> x);
// etc
static X<T, n> c();
protected: 
T data[N];
};

1(部分专业化的方法

template <class T>
class X<T, 3> {
public:
void d();
};
template <class T>
using X3 = X<T, 3>;

a( [Y]std::hash<'X3<'T'>'>std::hash<'X<'T、3'>'>相同,所以如果我重载X<'T、N'>X3<'T'>的哈希也可以工作b( [Y] 函数
d访问的 c( [N] 函数 a、b、c 不可
访问
d( [Y/N]X3<'T'> x =X3<'T'>::c((;如果C访问,将起作用

2(继承方法

template <class T>
class X3 : public X<T, 3> {
public:
void d();
};

a( [N]std::hash<'X3<'T'>'>std::hash<'X<'T、3'>'>不同,所以如果我为 X<'T、N'>、X3<</strong>'T'>重载哈希将不适用b( [Y] 函数 d 可访问 c

( [Y/N]函数a、b、c 是可访问的,但bc具有类似的强制转换问题(详见下文(d( [N] X3<'T'>
x =X3<'T'>:c((;不起作用,即使可访问

说明:
编译器知道如何将X3<'T'>转换为X<'T、3'>(因此将X3<'T'>作为参数传递给函数 b 有效(编译器不知道如何将 X<'T、3'> 转换为 X3<'T'>(因此将函数bc结果分配给X3<'T'>变量不起作用(

(设法通过创建一个移动构造函数'X3(X<'T, 3'>&&x( noexcept'来绕过它,但在这种情况下仍然存在 std::hash 问题(

有没有办法将这两种方法的优点结合起来?
(除了使用方法 1(并重写所有这样的方法:(

//...
X3<T> b(X3<T> x) {
return X<T, 3>::b(x);
}
//...  

(或方法2(和奇怪的转换,移动/复制构造函数,并且必须为std::hash之类的东西专门化几次模板(

根据我的经验,当您实际想要一个从模板继承的新类时,请使用继承方法 (2(。当部分特化与一般情况完全不同或根本没有定义一般情况时,只需声明一堆部分特化以使用 SFINAE,请使用方法 (1(。

如果您只想启用/禁用基于模板参数的类的方法,请使用 SFINAE。通过这种方式,您可以将所有定义集中在一个地方,并更轻松地推理它们。这是首选方法,除非您希望用户自行进行模板专用化 - 这通常不可取。

SFINAE 的例子:

template <class T, size_t N>
class X {
public:
void a() {...};
X<T, N> b(X<T, N> x);
// etc
static X<T, n> c() {...};
template<size_t uN = N, std::enable_if_t<uN==3,int>=0>
void d() {...};
protected: 
T data[N];
};

在这里,X<int,3> x; x.d();将编译,但X<int,2> x; x.d();不会因为d()方法被禁用,除非N==3

您可以在许多在线指南中阅读有关 SFINAE 在模板函数和类中的用法的更多信息(请注意,函数和类的语法完全不同(。