在Derived中检查Base类的模板参数

时间:2014-07-25 10:16:08

标签: c++ function

我有一个像

这样的基类
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&amp;的模板参数Derived不超过getMaxParameter()的返回值?

我可以做类似

的事情
DerivedA() {
  if (parameter > getMaxParameter()) 
    //...
}

但我不想在每个派生类中写这个。我可以在Base做这样的事吗?我不能称之为纯虚函数,但还有其他方法吗?

我不需要虚拟功能,它可以是例如取而代之的是Derived的成员变量。

3 个答案:

答案 0 :(得分:4)

您可以使用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构造函数。调用模板化构造函数but possible with the help of template type deduction and a dummy parameter

有点棘手
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>()) {
        // ...
    }
};

答案 1 :(得分:3)

如果在编译时无法使用static_assert因为派生类的getMaxParameter的返回值尚未知晓,则可以使用工厂...

#include <iostream>

template <int parameter>
struct Base {
  void verify () {
    if (parameter > this->getMaxParameter())
      std::cout << "Bigger\n";
    else
      std::cout << "Smaller\n";
  }
  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;
}

verified output

答案 2 :(得分:0)

该类在编译时创建为模板实例化。

您可以做的最好的事情是static_assert要检查的值是constexpr:

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");
};