使用类型特征的部分类专用化

Partial class specialization using type traits

本文关键字:分类 专用 类型 特征      更新时间:2023-10-16

我对C++很陌生,我遇到了一个问题,我似乎无法解决或找到有相同问题的其他人。

我有一个定义的类Polynomial

template<class C>
class Polynomial {
std::vector<C> coefficients;
...
public:
...
const double integral(double, double);
...
};

我需要确保,如果C是整型类型,则不能调用integral()方法。显然,这意味着使用类型特征,但是我已经尝试在方法本身上使用template<typename = typename std::enable_if<!std::is_integral<C>::value, C>::type>,尽管它可以编译,但现在我无法制作具有整型作为模板参数的对象。

然后我想,应该可以创建Polynomial类的部分特化,即具有浮点的类的专用化,一个具有积分,一个具有复数。类似的东西

template<typename C>
class Polynomial<typename std::enable_if<std::is_floating_point<C>::value, C>::type> : Polynomial<C> {
public:
const double integral(double, double);
};

然而,无论我怎么做,它似乎永远不会奏效。

我想我的问题是:如何使用类型特征作为专用化来指定类的部分专用化?

希望你能帮上忙。

你需要一个单独的基类来存储常见的东西,然后你可以像这样为Polynomial做模板专用化:

template<class C>
class PolynomialBase {
std::vector<C> coefficients;
};    
template <typename T, typename Enable = void>
class Polynomial;
template<typename C>
class Polynomial<C, typename std::enable_if<!std::is_integral<C>::value>::type> : PolynomialBase<C> {
public:
const double integral(double, double);
};    
template<typename C>
class Polynomial<C, typename std::enable_if<std::is_integral<C>::value>::type> : PolynomialBase<C> {};

玩得太晚了?

显然,您可以通过专业化来解决问题,而 krisz 的答案展示了一种可能的方法。

但是您可以通过SFINAE简单地启用/禁用integral()来解决它。

您无法检查C类型,因为 SFINAE 适用于特定于该方法的模板,而不是类的模板,因此您必须integral()模板方法。

通过示例

template <typename D = C>
std::enable_if_t<std::is_floating_point<D>::value, double>
integral (double, double)
{ return 1.0; }

这样,您可以检查默认为C类型的D类型。

以下是完整的编译示例

#include <vector>
#include <type_traits>
template <typename C>
class Polynomial
{
private:
std::vector<C> coefficients;
public:
template <typename D = C>
std::enable_if_t<std::is_floating_point<D>::value, double>
integral (double, double)
{ return 1.0; }
};
int main()
{
Polynomial<float>  pf;
Polynomial<int>    pi;
pf.integral(0.0, 0.0);  // compile
// pi.integral(0.0, 0.0);  // compilation error
}

此解决方案的问题是,如果您显式D类型,可能会被"劫持">

Polynomial<int>    pi;
// pi.integral(0.0, 0.0);  // compilation error
pi.integral<double>(0.0, 0.0); // hijacked: compile

为避免劫持问题,您可以修改SFINAE测试,以integral()强加CD是同一类型

所以如果你这样写

template <typename D = C>
std::enable_if_t<std::is_floating_point<D>::value
&& std::is_same<C, D>::value, double>
integral (double, double)
{ return 1.0; }

integral()不能再被劫持

Polynomial<int>    pi;
// pi.integral(0.0, 0.0);  // compilation error
// pi.integral<double>(0.0, 0.0); // compilation error