Using a nested name specifier in CRTP

Viewed 272

I'm using CRPT and need to access a parameter in the base class which is defined in the derived class. It works when used in a member function, but not in a (I'm guessing) compile time expression (the problem occurs when defining a type). The following code illustrates the problem:

#include <iostream>
#include <array>

template <typename impl_t>
struct base {
// no complaints
  void print () {
    std::cout << "Base, impl_t::i_q = " << impl_t::i_q << std::endl;
  }
// compiler error:
//                 clang++: no member named 'i_q' in 'deriv_t'
//                 g++:     incomplete type ‘deriv_t’ used in nested name specifier
  using vec_t = std::array<double, impl_t::i_q>;
};

struct deriv_t : public base<deriv_t> {
  static const std::size_t i_q = 1;
};

int main () {
  deriv_t d;
  d.print();
}

I'm just wondering what rules are broken here? The solution I've come up with is to define i_q alongside impl_t in the template, but would like to know if there is a more tidy way to solve the problem.

Solution:

Thanks to Evg here is the solution:

template <typename impl_t>
struct traits;

template <typename impl_t>
struct base_t {
  void print () {
    std::cout << "Base, impl_t::i_q = " << traits<impl_t>::i_q << std::endl;
  }
  using vec_t = std::array<double, traits<impl_t>::i_q>;
};

struct deriv_t;

template <>
struct traits<deriv_t> {
  static const std::size_t i_q = 1;
};
struct deriv_t : public base_t<deriv_t> {
};
1 Answers

impl_t is an incomplete type in base. You can solve the problem either using another template parameter or using a type traits technique:

template<class>
struct traits;

template<>
struct traits<deriv_t>
{
    static constexpr std::size_t i_q = 1;
};

...

void print () {
    std::cout << "Base, i_q = " << traits<impl_t>::i_q << std::endl;
}

using vec_t = std::array<double, traits<impl_t>::i_q>;

You don't have complaints in print() because at the point of its instantiation impl_t becomes a complete type.

Related