Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 30, 2015, 9:13:14 PM (9 years ago)
Author:
landauf
Message:

MultiType now supports strongly typed enum classes. Their values are cast to the underlying type.
MultiType now also uses additional static_asserts to ensure that it is only used with supported values.

Location:
code/branches/cpp11_v2
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • code/branches/cpp11_v2/src/libraries/network/synchronisable/Synchronisable.h

    r10996 r11002  
    207207  {
    208208    template <class T, bool = std::is_enum<T>::value>
    209     struct RealType;
     209    struct UnderlyingType;
    210210    template <class T>
    211     struct RealType<T, true> { typedef typename std::underlying_type<T>::type type; };
     211    struct UnderlyingType<T, true> { typedef typename std::underlying_type<T>::type type; };
    212212    template <class T>
    213     struct RealType<T, false> { typedef T type; };
     213    struct UnderlyingType<T, false> { typedef T type; };
    214214  }
    215215
     
    217217  void Synchronisable::registerVariable(T& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
    218218  {
    219     typedef typename detail::RealType<T>::type RealType;
     219    typedef typename detail::UnderlyingType<T>::type UnderlyingType;
    220220    if (bidirectional)
    221221    {
    222       syncList_.push_back(new SynchronisableVariableBidirectional<RealType>(reinterpret_cast<RealType&>(variable), mode, cb));
     222      syncList_.push_back(new SynchronisableVariableBidirectional<UnderlyingType>(reinterpret_cast<UnderlyingType&>(variable), mode, cb));
    223223      this->dataSize_ += syncList_.back()->getSize(state_);
    224224    }
    225225    else
    226226    {
    227       syncList_.push_back(new SynchronisableVariable<RealType>(reinterpret_cast<RealType&>(variable), mode, cb));
     227      syncList_.push_back(new SynchronisableVariable<UnderlyingType>(reinterpret_cast<UnderlyingType&>(variable), mode, cb));
    228228      if ( this->state_ == mode )
    229229        this->dataSize_ += syncList_.back()->getSize(state_);
     
    255255  void Synchronisable::registerVariable( std::set<T>& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
    256256  {
    257     typedef typename detail::RealType<T>::type RealType;
     257    typedef typename detail::UnderlyingType<T>::type UnderlyingType;
    258258    SynchronisableVariableBase* sv;
    259259    if (bidirectional)
    260       sv = new SynchronisableVariableBidirectional<std::set<RealType>>(reinterpret_cast<std::set<RealType>&>(variable), mode, cb);
     260      sv = new SynchronisableVariableBidirectional<std::set<UnderlyingType>>(reinterpret_cast<std::set<UnderlyingType>&>(variable), mode, cb);
    261261    else
    262       sv = new SynchronisableVariable<std::set<RealType>>(reinterpret_cast<std::set<RealType>&>(variable), mode, cb);
     262      sv = new SynchronisableVariable<std::set<UnderlyingType>>(reinterpret_cast<std::set<UnderlyingType>&>(variable), mode, cb);
    263263    syncList_.push_back(sv);
    264264    stringList_.push_back(sv);
  • code/branches/cpp11_v2/src/libraries/util/Math.h

    r10978 r11002  
    4747#include <cstdlib>
    4848#include <random>
     49#include <type_traits>
    4950
    5051#include <OgreMath.h>
     
    178179        @c Vector3 you get <tt>Vector3(0, 0, 0)</tt>.
    179180    */
    180     template <typename T>
    181     inline T zeroise()
     181    template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, T>::type
     182    inline /*T*/ zeroise()
    182183    {
    183184        // If you reach this code, you abused zeroise()!
    184185        static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
     186    }
     187    /// Implementation for enum classes: uses the underlying type to create a zero value.
     188    template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, T>::type
     189    inline /*T*/ zeroise()
     190    {
     191        return static_cast<T>(zeroise<typename std::underlying_type<T>::type>());
    185192    }
    186193
  • code/branches/cpp11_v2/src/libraries/util/MultiType.h

    r11001 r11002  
    183183            /// Returns the type of the current value.
    184184            inline const Type::Enum& getType() const { return this->type_; }
    185             /// Returns true if the type of the stored value is T.
    186             template <typename T> inline bool isType() const { return false; }
     185
     186            /// Returns true if the type of the stored value is T. Note: the actual implementations for all supported types are defined outside of the class.
     187            template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, bool>::type
     188            inline /*bool*/ isType() const
     189            {
     190                // If you reach this code, you used MultiType with an unsupported type T
     191                static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
     192                return false;
     193            }
     194            /// Implementation for enum classes: Returns true if the type of the stored value is the underlying type of T.
     195            template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, bool>::type
     196            inline /*bool*/ isType() const
     197            {
     198                return this->isType<typename std::underlying_type<T>::type>();
     199            }
    187200
    188201            /// Checks whether the value is a default one.
     
    215228            virtual bool setValue(const MultiType& other)            = 0;
    216229
     230            template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, bool>::type
     231            inline /*bool*/ setValue(const T& value)
     232            {
     233                // If you reach this code, you used MultiType with an unsupported type T
     234                static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
     235                return false;
     236            }
     237            template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, bool>::type
     238            inline /*bool*/ setValue(const T& value)
     239            {
     240                typedef typename std::underlying_type<T>::type UnderlyingType;
     241                return this->setValue(reinterpret_cast<const UnderlyingType&>(value));
     242            }
     243
    217244            virtual bool getValue(char*                 value) const = 0;
    218245            virtual bool getValue(unsigned char*        value) const = 0;
     
    239266            virtual bool getValue(orxonox::Degree*      value) const = 0;
    240267
     268            template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, bool>::type
     269            inline /*bool*/ getValue(T* value) const
     270            {
     271                // If you reach this code, you used MultiType with an unsupported type T
     272                static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
     273                return false;
     274            }
     275            template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, bool>::type
     276            inline /*bool*/ getValue(T* value) const
     277            {
     278                typedef typename std::underlying_type<T>::type UnderlyingType;
     279                return this->getValue(reinterpret_cast<UnderlyingType*>(value));
     280            }
     281
    241282            template <typename T> T get() const
    242283            {
     
    431472            }
    432473            /// Creates a new value container (works only with specialized types).
    433             template <typename T> inline void createNewValueContainer(const T& value)
     474            template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value>::type
     475            inline /*void*/ createNewValueContainer(const T& value)
    434476            {
    435477                // If you reach this code, you used MultiType with an unsupported type T
    436478                static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
     479            }
     480            /// Creates a new value container (implementation for enum classes that must be cast to the underlying type).
     481            template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value>::type
     482            inline /*void*/ createNewValueContainer(const T& value)
     483            {
     484                typedef typename std::underlying_type<T>::type UnderlyingType;
     485                this->createNewValueContainer<UnderlyingType>(reinterpret_cast<const UnderlyingType&>(value));
    437486            }
    438487
  • code/branches/cpp11_v2/test/util/MultiTypeTest.cc

    r10197 r11002  
    697697        EXPECT_TRUE(mt.null());
    698698    }
     699
     700    ///////////////////////////////
     701    // Strongly typed enum class //
     702    ///////////////////////////////
     703    enum class EnumWithChar : unsigned char
     704    {
     705        ValueA = 'A',
     706        ValueB = 'B',
     707        ValueC = 'C',
     708    };
     709    enum class EnumWithInt
     710    {
     711        Value1 = 50,
     712        Value2 = 0,
     713        Value3,
     714    };
     715
     716    TEST(MultiType, Enum_Constructor)
     717    {
     718        // Constructor:
     719        {
     720            MultiType mt = EnumWithChar::ValueA;
     721
     722            EXPECT_TRUE(mt.isType<EnumWithChar>());
     723            EXPECT_EQ(EnumWithChar::ValueA, mt.get<EnumWithChar>());
     724        }
     725        {
     726            MultiType mt = MultiType(EnumWithInt::Value1);
     727
     728            EXPECT_TRUE(mt.isType<EnumWithInt>());
     729            EXPECT_EQ(EnumWithInt::Value1, mt.get<EnumWithInt>());
     730        }
     731    }
     732
     733    TEST(MultiType, Enum_Assignment)
     734    {
     735        // operator=:
     736        MultiType mt;
     737        mt = EnumWithChar::ValueB;
     738
     739        EXPECT_TRUE(mt.isType<EnumWithChar>());
     740        EXPECT_EQ(EnumWithChar::ValueB, mt.get<EnumWithChar>());
     741    }
     742
     743    TEST(MultiType, Enum_Set)
     744    {
     745        // set(value):
     746        {
     747            MultiType mt;
     748            mt.set(EnumWithInt::Value2); // assign enum to an empty MultiType
     749
     750            EXPECT_TRUE(mt.isType<EnumWithInt>());
     751            EXPECT_EQ(EnumWithInt::Value2, mt.get<EnumWithInt>());
     752        }
     753        {
     754            MultiType mt = "string";
     755            mt.set(EnumWithChar::ValueC); // assign enum to a MultiType with type std::string
     756
     757            EXPECT_TRUE(mt.isType<std::string>());
     758            EXPECT_EQ("C", mt.get<std::string>());
     759        }
     760        {
     761            MultiType mt = EnumWithChar::ValueA;
     762            mt.set(EnumWithChar::ValueB); // assign enum to a MultiType with type std::string
     763
     764            EXPECT_TRUE(mt.isType<EnumWithChar>());
     765            EXPECT_EQ(EnumWithChar::ValueB, mt.get<EnumWithChar>());
     766        }
     767        {
     768            MultiType mt = EnumWithInt::Value3;
     769            mt.set("50"); // assign enum to a MultiType with type std::string
     770
     771            EXPECT_TRUE(mt.isType<EnumWithInt>());
     772            EXPECT_EQ(EnumWithInt::Value1, mt.get<EnumWithInt>());
     773        }
     774    }
     775
     776    TEST(MultiType, Enum_Force)
     777    {
     778        // force(value):
     779        {
     780            MultiType mt = "string";
     781            EXPECT_TRUE(mt.isType<std::string>());
     782            EXPECT_EQ("string", mt.get<std::string>());
     783
     784            mt.force<EnumWithChar>("C");
     785
     786            EXPECT_TRUE(mt.isType<EnumWithChar>());
     787            EXPECT_EQ(EnumWithChar::ValueC, mt.get<EnumWithChar>());
     788        }
     789        {
     790            MultiType mt = EnumWithChar::ValueA;
     791            EXPECT_TRUE(mt.isType<EnumWithChar>());
     792            EXPECT_EQ(EnumWithChar::ValueA, mt.get<EnumWithChar>());
     793
     794            mt.force<std::string>(EnumWithChar::ValueB);
     795
     796            EXPECT_TRUE(mt.isType<std::string>());
     797            EXPECT_EQ("B", mt.get<std::string>());
     798        }
     799    }
     800
     801    TEST(MultiType, Enum_Convert)
     802    {
     803        // convert():
     804        {
     805            MultiType mt = "C";
     806            mt.convert<EnumWithChar>();
     807
     808            EXPECT_TRUE(mt.isType<EnumWithChar>());
     809            EXPECT_EQ(EnumWithChar::ValueC, mt.get<EnumWithChar>());
     810        }
     811        {
     812            MultiType mt = EnumWithChar::ValueA;
     813            mt.convert<std::string>();
     814
     815            EXPECT_TRUE(mt.isType<std::string>());
     816            EXPECT_EQ("A", mt.get<std::string>());
     817        }
     818    }
     819
     820    TEST(MultiType, Enum_Reset)
     821    {
     822        // reset():
     823        {
     824            MultiType mt = EnumWithChar::ValueA;
     825            mt.reset<EnumWithChar>();
     826
     827            EXPECT_TRUE(mt.isType<EnumWithChar>());
     828            EXPECT_TRUE(mt.isType<unsigned char>());
     829            EXPECT_EQ('\0', mt.get<unsigned char>());
     830        }
     831        {
     832            MultiType mt = "string";
     833            mt.reset<EnumWithInt>();
     834
     835            EXPECT_TRUE(mt.isType<EnumWithInt>());
     836            EXPECT_TRUE(mt.isType<int>());
     837            EXPECT_EQ(0, mt.get<int>());
     838        }
     839    }
     840
     841    TEST(MultiType, Enum_IsType)
     842    {
     843        // isType():
     844        {
     845            MultiType mt = EnumWithChar::ValueB;
     846            EXPECT_TRUE(mt.isType<EnumWithChar>());
     847            EXPECT_TRUE(mt.isType<unsigned char>());
     848            EXPECT_FALSE(mt.isType<char>());
     849            EXPECT_FALSE(mt.isType<int>());
     850            EXPECT_FALSE(mt.isType<bool>());
     851            EXPECT_FALSE(mt.isType<std::string>());
     852        }
     853        {
     854            MultiType mt = EnumWithInt::Value3;
     855            EXPECT_TRUE(mt.isType<EnumWithInt>());
     856            EXPECT_TRUE(mt.isType<int>());
     857            EXPECT_FALSE(mt.isType<unsigned char>());
     858            EXPECT_FALSE(mt.isType<char>());
     859            EXPECT_FALSE(mt.isType<bool>());
     860            EXPECT_FALSE(mt.isType<std::string>());
     861        }
     862    }
     863
     864    TEST(MultiType, Enum_ConversionOperator)
     865    {
     866        // conversion operator:
     867        {
     868            MultiType mt = EnumWithChar::ValueA;
     869            EnumWithChar value = mt;
     870            EXPECT_EQ(EnumWithChar::ValueA, value);
     871        }
     872        {
     873            MultiType mt = 'B';
     874            EnumWithChar value = mt;
     875            EXPECT_EQ(EnumWithChar::ValueB, value);
     876        }
     877        {
     878            MultiType mt = EnumWithInt::Value1;
     879            std::string value = mt;
     880            EXPECT_EQ("50", value);
     881        }
     882    }
     883
     884    TEST(MultiType, Enum_GetValue)
     885    {
     886        // getValue():
     887        {
     888            MultiType mt = EnumWithChar::ValueA;
     889            EnumWithChar value;
     890            mt.getValue(&value);
     891            EXPECT_EQ(EnumWithChar::ValueA, value);
     892        }
     893        {
     894            MultiType mt = 'B';
     895            EnumWithChar value;
     896            mt.getValue(&value);
     897            EXPECT_EQ(EnumWithChar::ValueB, value);
     898        }
     899        {
     900            MultiType mt = EnumWithInt::Value1;
     901            std::string value;
     902            mt.getValue(&value);
     903            EXPECT_EQ("50", value);
     904        }
     905    }
     906
     907    TEST(MultiType, Enum_Get)
     908    {
     909        // get():
     910        {
     911            MultiType mt = EnumWithChar::ValueB;
     912            EXPECT_EQ(EnumWithChar::ValueB, mt.get<EnumWithChar>());
     913
     914            EXPECT_EQ('B', mt.get<unsigned char>());
     915            EXPECT_EQ("B", mt.get<std::string>());
     916            EXPECT_EQ(66, mt.get<int>());
     917            EXPECT_TRUE(mt.get<bool>());
     918        }
     919        {
     920            MultiType mt = EnumWithInt::Value1;
     921            EXPECT_EQ(EnumWithInt::Value1, mt.get<EnumWithInt>());
     922
     923            EXPECT_EQ('2', mt.get<unsigned char>());
     924            EXPECT_EQ("50", mt.get<std::string>());
     925            EXPECT_EQ(50, mt.get<int>());
     926            EXPECT_TRUE(mt.get<bool>());
     927        }
     928        {
     929            MultiType mt = EnumWithInt::Value2;
     930            EXPECT_EQ(EnumWithInt::Value2, mt.get<EnumWithInt>());
     931
     932            EXPECT_EQ('\0', mt.get<unsigned char>());
     933            EXPECT_EQ("0", mt.get<std::string>());
     934            EXPECT_EQ(0, mt.get<int>());
     935            EXPECT_FALSE(mt.get<bool>());
     936        }
     937    }
    699938}
Note: See TracChangeset for help on using the changeset viewer.