从一个CRTP子类访问另一个子类的数据/方法

时间:2013-07-09 21:17:59

标签: c++ class templates crtp

“Model”是一个基类,用于定义每个派生模型必须具有的数据结构和方法。 “Filter”是一个使用Model的数据结构和方法的基类(都具有在Model基类中定义的相同接口)。将有多个派生模型和多个派生过滤器。每个派生的过滤器都应该能够对任何派生的模型起作用。模型独立于Filter。由于速度很重要,我正在尝试使用奇怪的重复模板模式(CRTP)进行静态多态。理想情况下,Filter使用的Model中的方法应该是可以使用的。这个班级设计的一个开端是:

template <typename DerivedModel>
class Model {
 public:
  Model() {}
  double f(const double x) {
   return static_cast<DerivedModel*>(this)->f(x);
  } // f
}; // Model

class Model1 : Model<Model1> {
// Curiously Recurring Template Pattern
 public:
  Model1() : Model() {}
  double f(const double x) { return x; }
}; // Model1

template <typename DerivedFilter>
class Filter {
 public:
  double b_;
  Filter(const double b) : b_(b) {}
  double step() {
   return static_cast<DerivedFilter*>(this)->step();
  } // step
}; // Filter

现在我们需要一种机制来允许Filter访问Model。尝试多重继承只是为了看它是否编译:

template <typename DerivedModel>
class Filter2A : public Filter<Filter2A>, public DerivedModel {
}; // Filter2A

这失败了(使用gcc 4.7.1,没有特殊的开关):

error: type/value mismatch at argument 1 in template parameter list for ‘template<class DerivedFilter> class Filter’
expected a type, got ‘Filter2A’

基于读取相关的stackoverflow帖子,让我们使用模板模板参数。另外,我将代替MI,将一个Model放在Filter的新代码中:

template<typename DerivedModel, template<class> class DerivedFilter>
class Filter {
 public:
  DerivedModel myModel; // Filter "has a" Model
  double b_;
  Filter(const double b) : b_(b) {}
  double step() {
   return static_cast<DerivedFilter*>(this)->step(); // ERROR
  } // step
}; // Filter

template<typename DerivedModel>
class Filter1 : public Filter< DerivedModel, Filter1 > { // CRTP
 public:
  Filter1(const double b) : Filter< DerivedModel, Filter1 >(b) {}
  double step() { return b_; } // "b_ was not declared in this scope"
}; // Filter1

这样做 - 除了static_cast行:

In member function ‘double Filter<DerivedModel, DerivedFilter>::step()’:
error: expected type-specifier before ‘DerivedFilter’
expected ‘>’ before ‘DerivedFilter’
...

因此模板模板参数DerivedModel需要不同的语法才能访问Model的方法?是否有一个typedef修复了这个问题(尝试了一些但没有成功)。

另外,我不明白第二个问题 - Filter1的b_在Filter1中不再可访问,即使一切都是公开的。 (可以通过使用Filter&lt; DerivedModel,Filter1&gt; :: b_替换b_来修复)。对于更简单的CRTP代码示例,这不是必需的。

1 个答案:

答案 0 :(得分:2)

只要你正确地输入了班级名称,你的第一次尝试应该可行:

class Filter2A : public Filter<Filter2A<DerivedModel> >, public DerivedModel {

或者,如果您使用正确的static_cast语法,则第二次尝试应该有效:

    return static_cast<DerivedFilter<DerivedModel>*>(this)->step();

您需要在这些情况下命名特定类型,而不是提及编译器无法转换为实际类型的模板名称。模板名称本身(没有要解析为特定类型的所有参数)不会为编译器提供解析实际类型所需的信息(它需要计算布局信息,查找符号等)。 / p>

关于查找b_符号,这是一个依赖类型的继承类型的成员(意味着编译器在声明模板时不知道类型)。您需要向编译器提供此符号是依赖符号的提示,并且必须在实例化时查找。尝试使用this->b_而不是b_。或者,使用类命名空间限定符。然后,编译器将符号视为依赖符号,并在模板实例化时间而不是模板定义时解析它。