检查派生中基类的模板参数

Check template parameter of Base class in Derived

本文关键字:参数 基类 派生 检查      更新时间:2023-10-16

我有一个像

这样的基类
template <int parameter>
class Base {
public:
  virtual int getMaxParameter() = 0;      
}

,我选择了多个派生类中的一个,比如

template <int parameter>
class DerivedA : public Base<parameter> 
{
public:
  int getMaxParameter() { return 2; }
}
通过

const int p = 3;
Base<p>* base;
switch (unreleated_input_int) {
  case 1:
    base = new DerivedA<p>(); break;
  case 2:
    base = new DerivedB<p>(); break;
  // ...
}

问:如何确保Base &派生不超过getMaxParameter()的返回值?

我可以这样写

DerivedA() {
  if (parameter > getMaxParameter()) 
    //...
}

但是我不想在每个派生类中都写这个。我能在Base中做这样的事情吗?我不能调用纯虚函数,但还有其他方法吗?

我不需要虚函数,它可以是派生的成员变量。

您可以使用static_assert(编译时断言)使DerivedA<3>(其中3 < 2不满足条件)编译失败(如果您喜欢的话):

template <int parameter>
class DerivedA : public Base<parameter> 
{
    static_assert(parameter < 2, "Parameter for DerivedA is too large!");
    //            ^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //              condition           message in case of error
public:
};

这将给你一个很好的提示,如果你写DerivedA<3>:

错误:静态断言失败:DerivedA参数太大!

你可以把2变成constexpr成员。constexpr表示它在编译时是已知的,这是static_assert所需要的:

template <int parameter>
class DerivedA : public Base<parameter> 
{
    static constexpr int maxParameter = 2;
    static_assert(parameter < maxParameter, "Parameter for DerivedA is too large!");
public:
};

如果您不喜欢在每个派生类中都有这些代码,您可以将其移动到Base,它现在接受两个参数:实际参数和最大值。它的缺点是错误消息不能包含派生类的名称,但我想这不是很重要:

template <int parameter, int maxParameter>
class Base
{
    static_assert(parameter < maxParameter, "Parameter is too large!");
};
template <int parameter>
class DerivedA : public Base<parameter, 2> 
{
};

如果您不喜欢Base类的第二个模板参数(就像您的问题中添加的工厂代码中的问题一样),您可以将其移动到Base构造函数。调用模板化的构造函数有点棘手,但可以借助模板类型推断和虚拟参数:

template <int parameter>
class Base
{
public:
    template <int maxParameter>
    Base(std::integral_constant<int, maxParameter>) {
        static_assert(parameter < maxParameter, "Parameter is too large!");
    }
};
template <int parameter>
class DerivedA : public Base<parameter> 
{
public:
    DerivedA() : Base(std::integral_constant<int, 2>()) {
        // ...
    }
};

如果你不能在编译时使用static_assert,因为你的派生类的getMaxParameter的返回值还不知道,你可以使用工厂…

#include <iostream>
template <int parameter>
struct Base {
  void verify () {
    if (parameter > this->getMaxParameter())
      std::cout << "Biggern";
    else
      std::cout << "Smallern";
  }
  virtual int getMaxParameter() = 0;
};
template <int parameter>
struct Derived : public Base<parameter> {
  virtual int getMaxParameter() { return 0; }
};
template <int parameter>
Base<parameter> * make_and_verify () {
  Base<parameter> * result = new Derived<parameter>;
  result->verify();
  return result;
}
int main() {
  Base<0> * foo = make_and_verify<0>();
  Base<1> * bar = make_and_verify<1>();
  return 0;
}

验证输出

类是在编译时作为模板实例化创建的。

如果要检查的值是constexpr,则最好使用static_assert:

template <int parameter>
class DerivedA : public Base<parameter> 
{
public:
  static_assert(parameter < 2, "wrong template parameter value");
  int getMaxParameter() { return 2; }
};

或者,假设您可以将getMaxParameter设置为constexpr:

template <int parameter>
class DerivedA : public Base<parameter> 
{
public:
  constexpr int getMaxParameter() { return 2; }
  static_assert(parameter < getMaxParameter(), "wrong template parameter");
};