Pergunta

"Model" is a base class defining the data structures and methods every derived model must have. "Filter" is a base class that uses a Model's data structures and methods (all with the same interface defined in the Model base class). There will be multiple derived Models and multiple derived Filters. Each derived Filter should be able to act on any derived Model. Model is independent of Filter. Since speed is important, I am trying static polymorphism using the Curiously Recurring Template Pattern (CRTP). Ideally, the methods in Model used by Filter should be inlinable. A start at this class design is:

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

Now we need a mechanism to allow Filter access to Model. Try multiple inheritance just to see if it compiles:

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

This fails (using gcc 4.7.1, no special switches):

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

Based on reading related stackoverflow posts, let's use a template template argument instead. Also, instead of MI, I'll put a Model inside of the new code for 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

This works - except for the static_cast line:

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

So the template-template parameter DerivedModel needs a different syntax to access Model's methods? Is there a typedef that fixes this (tried a few things but no success).

Also, I don't understand a 2nd issue - Filter's b_ is no longer accessible in Filter1 even though everything is public. (can fix by replacing b_ with Filter< DerivedModel, Filter1 >::b_ ). This was not necessary with the simpler CRTP code example.

Foi útil?

Solução

Your first attempt should probably work, as long as you put the class name in properly:

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

Alternatively, your second attempt should work if you use the correct static_cast syntax:

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

You need to name a specific type in these situations, rather than mentioning a template name that the compiler can't turn into a real type. A template name by itself (without all the arguments to resolve to a specific type) doesn't provide the compiler the information it needs to resolve the actual type (which it needs to compute layout information, look up symbols, etc.).

With regard to finding the b_ symbol, this is a member of an inherited type that is a dependent type (meaning the compiler doesn't know the type when the template was declared). You need to give the compiler a hint that this symbol is a dependent symbol and must be looked up at instantiation time. Try using this->b_ instead of just b_. Or, use a class namespace qualifier. The compiler will then treat the symbol as a dependent symbol and resolve it at template instantiation time rather than template definition time.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top