mercredi 22 septembre 2021

C++ Access to not yet defined member of template parameter

Doing some Metaprogramming with c++11.

I want to build an EnumWrapper which can be used for switch statements and as keywords for maps but still has object-like properties, like Java Enumerations.

Having the classes:

#include <string>
#include <vector>

template<typename T, int len>
class Enum
{
  private:
    typename T::Value value; // invalid use of incomplete Type Planet

  public:
    Enum() = delete;

    constexpr Enum( typename T::Value key ) : value( key ) // invalid use of incomplete Type Planet
    {
    }

    // Allow switch and comparisons.
    operator typename T::Value() const // invalid use of incomplete Type Planet
    {
        return value;
    }

    T& operator=( const T& other )
    {
        this->value = other.value;
        return *this;
    }

    inline typename T::Value getValue() // invalid use of incomplete Type Planet
    {
        return value;
    }

    explicit operator bool() = delete;

    Enum& operator=( const Enum& p )
    {
        this->value = p.value;
        return *this;
    }

    static inline int length()
    {
        return len;
    }

    static std::vector<T> values()
    {
        std::vector<T> values;
        values.reserve( length() );

        for ( int i = 0; i < length(); i++ )
        {
            values.push_back( (typename T::Value)i ); // This is fine for some reason
        }

        return values;
    }

    static T getMember( std::string name )
    {
        for ( T p : values() )
        {
            if ( p.name() == name )
            {
                return p;
            }
        }
    }
};


class Planet : Enum<Planet, 3>
{
  public:
    enum Value
    {
        MERCURY,
        VENUS,
        EARTH
    }
    
    std::string name()
    {
         switch(this->getValue())
         {
             case MERCURY:
                 return "Mercury";
             case EARTH:
                 return "Mercury";
             case VENUS:
                 return "Mercury";
         }
    }
};

The compiler gives several "invalid use of incomplete Type Planet" messages.

When merging the classes into one single class, the code compiles and works as intendet. But reuseablility and maintainability is not given with a merged approach.

Can someone help me with this error messages?

Just tell me, if further information is needed or wanted.

Edit: My inteded use is something like this:

int main()
{
    Planet planet        = Planet::EARTH;
    Planet invalidPlanet = Planet( (Planet::Value)5 );

    // attributes with enum working
    std::cout << "My Planet is named " << planet.name() << std::endl;
    Planet venus = Planet::VENUS;
    std::cout << "Gravity of Venus is " << venus.gravitation() << std::endl;

    // Switch working
    switch ( planet )
    {
    case Planet::VENUS:
        std::cout << "Venus found." << std::endl;
        break;
    case Planet::EARTH:
        std::cout << "Earth found." << std::endl;
        break;
    default:
        std::cout << "Nothing found." << std::endl;
        break;
    }

    // simple comparison
    bool isEarth = planet == Planet::EARTH; // true
    bool isVenus = planet == Planet::VENUS; // false

    std::cout << "Planet is earth: " << ( isEarth ? "true" : "false" ) << std::endl;
    std::cout << "Planet is venus: " << ( isVenus ? "true" : "false" ) << std::endl;

    // works in Map
    std::map<Planet, std::string> myMap;
    myMap[ planet ] = "MyEarth";
    
    std::cout << "chosen planet: " << myMap[ Planet::MERCURY ] << std::endl;
    std::cout << "chosen planet: " << myMap[ Planet::EARTH ] << std::endl;

    // Map is not bound to object but bound to enum integer
    Planet fakeEarth = Planet::EARTH;
    std::cout << "chosen planet: " << myMap[ fakeEarth ] << std::endl;

    return 1;
}

Aucun commentaire:

Enregistrer un commentaire