“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代码示例,这不是必需的。
答案 0 :(得分:2)
只要你正确地输入了班级名称,你的第一次尝试应该可行:
class Filter2A : public Filter<Filter2A<DerivedModel> >, public DerivedModel {
或者,如果您使用正确的static_cast
语法,则第二次尝试应该有效:
return static_cast<DerivedFilter<DerivedModel>*>(this)->step();
您需要在这些情况下命名特定类型,而不是提及编译器无法转换为实际类型的模板名称。模板名称本身(没有要解析为特定类型的所有参数)不会为编译器提供解析实际类型所需的信息(它需要计算布局信息,查找符号等)。 / p>
关于查找b_
符号,这是一个依赖类型的继承类型的成员(意味着编译器在声明模板时不知道类型)。您需要向编译器提供此符号是依赖符号的提示,并且必须在实例化时查找。尝试使用this->b_
而不是b_
。或者,使用类命名空间限定符。然后,编译器将符号视为依赖符号,并在模板实例化时间而不是模板定义时解析它。