【问题标题】:access data/methods from one CRTP child class by another另一个从一个 CRTP 子类访问数据/方法
【发布时间】:2013-07-07 15:51:59
【问题描述】:

“模型”是定义每个派生模型必须具有的数据结构和方法的基类。 “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帖子,让我们改用模板模板参数。另外,我将在 Filter 的新代码中放置一个模型,而不是 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 ‘>’ before ‘DerivedFilter’
...

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

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

【问题讨论】:

    标签: c++ class templates crtp


    【解决方案1】:

    只要你正确输入类名,你的第一次尝试应该会成功:

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

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

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

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

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

    【讨论】:

    • 尽管投票数很少,但仍要感谢彻底的解决方案。为了解析符号,为了方便起见,我添加了“typedef Filter F;”行然后可以输入“F::b_”等
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    • 2011-04-03
    • 2017-05-12
    • 2012-05-03
    • 2017-01-03
    • 2012-03-19
    • 2015-01-21
    相关资源
    最近更新 更多