"No member named" incomplete type in multi-level CRTP

119 Views Asked by At

I have encountered an incomplete type error in designing my library's CRTP inheritance structure. I am cognizant of the fact that this might possibly be solved by way of type traits but I do not even know where to begin and would like some guidance in that regard.

Roughly speaking, Alg and Geo are two interfaces that inherit from a shared base. Alg is fairly straightforward but Geo is a bit more complex in that it takes as a template parameter a class deriving from Alg. The incomplete type error is in reference to this functionality. Minimal reproducible example

The following skeleton illustrates the problem at hand.

template <typename Derived>
struct FitCRTP {
    Derived& derived() { return static_cast<Derived&>(*this); }
    Derived const& derived() const { return static_cast<Derived const&>(*this); }
};

template <typename Derived>
class FitBase : public FitCRTP<Derived> {
    friend class FitCRTP<Derived>;
    
    protected:
        FitBase() {}
        explicit FitBase(const Matrix& data) {
            this->derived().fit(data);
        }
};

template <typename Derived> 
class Alg : public FitBase<Derived> {
    friend class FitBase<Derived>;

    public:
        void fit (const Matrix& data) { 
            this->derived().compute(data);
        }

    protected:
        // constructors and misc functions ...
    }
};

template <typename Derived, class A,
    class = std::enable_if_t<std::is_base_of_v<Alg<A>, A>>> 
    class Geo : public FitBase<Geo<Derived, A>> {
        friend class FitBase<Geo<Derived, A>>;

        public:
            void fit (const Matrix& data) {        
                this->derived().compute(data, A(data).getGuess());    // <-- Problem line!
            }

        protected:
            // constructors and misc functions ...
        }
    };

Below is an example of one of A's derived classes and a usage example.

template <class A>
class SpathSVD : public Geo<SpathSVD<A>, A> {
    friend class Geo<SpathSVD<A>, A>;
    typedef Geo<SpathSVD<A>, A> Base;
public:
    SpathSVD<A> : Base() {}
    SpathSVD<A> (const Matrix& data) : Base(data) {}

protected:
    SpathSVD& compute (const Matrix& data, Guess g) {
        // Algorithm implementation ...
    }
}

int main() {
    SpathSVD<SomeAlgVariant> S;
    S.fit(data);
}

The error occurs because the compute function cannot be found in Geo<SpathSVD<SomeAlgVariant>, SomeAlgVariant>. How can I fix this?

0

There are 0 best solutions below