Home > Back-end >  Why do I get "invalid use of incomplete type", when the class is fully defined?
Why do I get "invalid use of incomplete type", when the class is fully defined?

Time:09-17

I know this type of errors occur when a base class is only forward declared, but in my case it's fully implemented as far as I can tell:

I'm trying to create a unit system which would only compile if the correct units are used, employing literals and algebraic operators.

I start with a base class Units which is just a wrapper over T, and is inherited by all the other units.

Then I define the allowed algebraic operators, which should return the correct units.

I get

error: invalid use of incomplete type ‘class Units<T>’
[build]   107 |     return Mps{static_cast<T>(rhs) / static_cast<T>(lhs)};

for this code:

template<typename T>
class Units
{
protected:
    T val;
public:
    constexpr explicit Units(T val) : val(val) { }
    constexpr explicit operator T&() { return val; }
    constexpr explicit operator T() const { return val; }
    constexpr auto operator<=>(const Units<T> rhs) {
        return val <=> rhs.val; 
    }
    constexpr bool operator==(const Units<T> rhs) const { return val == rhs.val; }

};


template<typename T>
class Meters : public Units<T>
{
    using typename Units<T>::Units;
};

template<typename T>
class Seconds : public Units<T>
{
    using typename Units<T>::Units;
};

template<typename T>
class Mps : public Units<T>
{
    using typename Units<T>::Units; 
};


constexpr Meters<long double> operator "" _km(long double km) {
    return Meters<long double>{1000 * km};
}


constexpr Seconds<long double> operator "" _s(long double s) {
    return Seconds<long double>{s};
}


constexpr Mps<long double> operator "" _mps(long double s) {
    return Mps<long double>{s};
}


template<typename T>
constexpr Mps<T> operator / (const Meters<T> &&rhs, const Seconds<T> &&lhs) {
    return Mps{static_cast<T>(rhs) / static_cast<T>(lhs)};
}


int main() {
    return 1_km / 2_s == 500_mps
}

CodePudding user response:

Looks like the compiler is confused and the warning is misleading. Provide the missing template argument to fix it:

return Mps<T>{static_cast<T>(rhs) / static_cast<T>(lhs)};
          ^^^

You can (probably) define a deduction guide if you wish to avoid specifying the argument explicitly.


Other issues:

  • Missing semicolon.
  • Your operators are for floating point, but you use integer in 1_km; that won't work. Either use floating point literal, or add an overload for integers.
  • using typename Units<T>::Units; is wrong. Lose the typename.
  • Related