0

“模型”是定义每个派生模型必须具有的数据结构和方法的基类。“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

现在我们需要一种机制来允许过滤器访问模型。尝试多重继承,看看它是否编译:

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:

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 ‘&gt;’ before ‘DerivedFilter’
...

那么模板模板参数 DerivedModel 需要不同的语法来访问 Model 的方法吗?是否有一个 typedef 可以解决这个问题(尝试了一些事情但没有成功)。

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

4

1 回答 1

2

只要您正确输入类名,您的第一次尝试就应该可以工作:

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

或者,如果您使用正确的static_cast语法,您的第二次尝试应该会起作用:

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

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

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

于 2013-07-09T21:31:55.997 回答