CRTP: function with derived-based argument

305 views Asked by At

Here's a minimal version of what I'm trying to do:

template<typename D>
struct Base {

        void common() {
                // ... do something ...
                static_cast<D *>(this)->impl();
                // ... do something ...
        }

        void common_with_arg(typename D::Arg arg) {
                // ... do something ...
                static_cast<D *>(this)->impl_with_arg(arg);
                // ... do something more ...
        }
};

struct Derived : Base<Derived> {
        void impl() { }

        using Arg = int;
        void impl_with_arg(Arg arg) { }

};

Base::common() and Derived::impl() work OK (as expected). Base::common_with_arg() and Derived::impl_with_arg(), however, do not.

With gcc, for example, I get the following error:

1.cc: In instantiation of ‘struct Base<Derived>’:
1.cc:18:18:   required from here
1.cc:11:7: error: invalid use of incomplete type ‘struct Derived’
  void common_with_arg(typename D::Arg arg) {
       ^~~~~~~~~~~~~~~
1.cc:18:8: note: forward declaration of ‘struct Derived’
 struct Derived : Base<Derived> {

Intuitively (without understanding all details about template instantiation), this seems like a sensible error. Is there another way to achieve the same functionality?

1

There are 1 answers

2
Vittorio Romeo On BEST ANSWER
void common_with_arg(typename D::Arg arg)
//                            ^^^^^^

You cannot access D::Arg here, as the definition of Derived would be required. But the definition is never available as the Base template is being instantiated here...

struct Derived : Base<Derived> { 
//               ^^^^^^^^^^^^^

...where Derived is not yet fully-defined.


One possible workaround is making common_with_arg a function template:

template <typename T>
void common_with_arg(T&& arg) {
        // ... do something ...
        static_cast<D *>(this)->impl_with_arg(std::forward<T>(arg));
        // ... do something more ...
}

example on wandbox


If you really need the Arg type alias, read this question:
"C++ static polymorphism (CRTP) and using typedefs from derived classes".