【问题标题】:Declare member function only for specific template instantiation of class仅为类的特定模板实例化声明成员函数
【发布时间】:2016-07-13 06:58:47
【问题描述】:

是否可以只为类的特定模板实例声明成员函数?这就是我想要这样做的原因:

// Polynomial<N> is a polynomial of degree N
template<int N>
class Polynomial {
public:
    //... various shared methods e.g...
    double eval(double x) const;
    Polynomial<N-1> derivative() const;
    Polynomial<N+1> integralFrom(double x0) const;
    // ... various shared operators etc.

    double zero() const; // only want Polynomial<1> to support this
    // only want Polynomial<2> and Polynomial<1> to support the following
    //     because the solutions rapidly become too difficult to implement
    std::vector<double> zeros() const;
    std::vector<double> stationaryPoints() const { return derivative().zeros();}

private:
    std::array<double,2> coeffs;
}

我目前的解决方法是从Polynomial&lt;N&gt;::zeros()N&gt;2 抛出一个异常,但在编译时检测到问题会很好。

【问题讨论】:

  • 模板专业化是否适合您?
  • 如果 C++11 可用,您可以使用static_assert(N &lt;= 2, "Incorrect template argument.") 代替throw。它可以防止编译时出现不需要的功能。
  • 无论如何你都需要专业化(由于Polynomial&lt;N-1&gt;
  • @DieterLücking 是的。 Polynomial&lt;0&gt;::derivative 不能定义为我的示例中声明的。但是怎么做呢?如何从一些模板实例中省略一些成员函数?我可以声明它们但不定义它们吗?
  • 这是基本的,一个专门的类是一个完全不同的类,你可以在实例化之前不知道模板的情况下使用任何模板。

标签: c++ templates c++11


【解决方案1】:

您也可以使用std::enable_if 来 SFINAE 消除归零功能。

template< int I >
class Poly {

public:
    template<int Ib = I, typename = std::enable_if_t<Ib == 1> > 
    double zero() 
    {
        return 42;
    }
};

int main()
{
    Poly< 10 > does_not_compile;
    does_not_compile.zero();

    //Poly< 1 >  compile;
    //compile.zero();
}

【讨论】:

  • 这在技术上是一个格式错误的程序,不需要诊断。
  • 为什么?我违反了什么规则?
【解决方案2】:

您可以使用 CRTP 在知道派生类的基类中实现 zeroszero

然后有条件地从具有zeros 和/或zero 的那个派生,或者没有。

template<class P>
struct zeros { /* todo */ };

template<class P>
struct zero:zeros<P> { /* todo */ };

struct nozero {};

template<int N>
struxt Polynomial:
  std::conditional_t<
    (N==1),
    zero<Polynomial<N>>,
    std::conditional_t<
      (N==2),
      zeros<Polynomial<N>>,
      nozero
    >
  >
{
  // body
};

【讨论】:

    【解决方案3】:

    您的解决方案是模板专业化,在这种情况下是完全专业化。

    但是,我认为您需要考虑您的设计。一般来说,为不同的情况定义不同的接口并不是一个好主意,因为你没有利用抽象。

    例如,考虑一下您的 stationaPoints() 函数。此函数不应该可用于多项式,因为导数是不具有 zeros() 函数的多项式。您的解决方案是将 zeros 函数添加到多项式 以使界面均匀化。

    对于你的情况,我猜你想要一个解决方案,它在多项式类型中包含一个 N-1 c 向量,其中包含零和一个 zero(i) 函数来获取它们。像这样的:

    template <int N>
    class Polynomial {
        double _coefs[N+1];
        double _zeros[N];
    public:
        double zero(size_t i) const { assert(i<N); return _zeros[i]; }
        // ...
    };
    

    在这种情况下,您可以决定计算 de zeros 的策略,具体取决于您的应用程序:构造函数?添加一个布尔值以了解它是否已计算,然后在第一次调用为零时计算它,等等...

    我想这个解决方案对您来说可能更有趣,因为如果您更喜欢使用 c 向量来存储系数,您不会喜欢 zeros() 函数的基于向量的接口,对吗?

    【讨论】:

    • Polynomial&lt;N&gt; 在我的问题中是 N 阶多项式,这意味着它具有 N+1 个系数。你介意修改你的答案吗?
    • 另外,你能推荐一个更好的设计吗?我当前的解决方案确实存储了一系列系数;我将编辑问题以显示它。
    猜你喜欢
    • 2011-01-30
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多