diff --git a/include/etl/utility.h b/include/etl/utility.h index 52cf0d37..5146eb3e 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -672,6 +672,56 @@ namespace etl } }; #endif + + //***************************************************************************** + /// A tag that can be used as a concrete object to identify a type. + //***************************************************************************** + template + struct type_tag + { + typedef T type; + typedef typename etl::remove_cvref::type underlying_type; + }; + + //*********************************** + /// Equality operator for type_tag + //*********************************** + template + ETL_CONSTEXPR bool operator ==(etl::type_tag, etl::type_tag) + { + return etl::is_same, etl::type_tag >::value; + } + + //*********************************** + /// Inequality operator for type_tag + //*********************************** + template + ETL_CONSTEXPR bool operator !=(etl::type_tag, etl::type_tag) + { + return !etl::is_same, etl::type_tag >::value; + } + +#if ETL_USING_CPP11 + //*********************************** + /// type_tag type + //*********************************** + template + using type_tag_t = typename etl::type_tag::type; + + //*********************************** + /// type_tag underlying type + //*********************************** + template + using type_tag_underlying_t = typename etl::type_tag::underlying_type; +#endif + +#if ETL_USING_CPP17 + //*********************************** + /// constexpr type_tag value + //*********************************** + template + inline constexpr etl::type_tag type_tag_v = etl::type_tag{}; +#endif } #endif diff --git a/test/test_utility.cpp b/test/test_utility.cpp index cb386b2f..f193f58f 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -33,6 +33,7 @@ SOFTWARE. #include #include #include +#include #include "data.h" @@ -665,5 +666,71 @@ namespace CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl(etl::move(u4))); CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl(etl::move(u4))); } + + //********************************* + TEST(test_type_tag) + { + using TypeTag1 = etl::type_tag; + using TypeTag2 = etl::type_tag; + using TypeTag3 = etl::type_tag; + + TypeTag1 typeTag1; + TypeTag2 typeTag2; + TypeTag3 typeTag3; + + CHECK_TRUE(typeTag1 == typeTag1); + CHECK_TRUE(typeTag2 == typeTag2); + CHECK_TRUE(typeTag3 == typeTag3); + + CHECK_FALSE(typeTag1 == typeTag2); + CHECK_FALSE(typeTag2 == typeTag3); + CHECK_FALSE(typeTag3 == typeTag1); + + CHECK_FALSE(typeTag1 != typeTag1); + CHECK_FALSE(typeTag2 != typeTag2); + CHECK_FALSE(typeTag3 != typeTag3); + + CHECK_TRUE(typeTag1 != typeTag2); + CHECK_TRUE(typeTag2 != typeTag3); + CHECK_TRUE(typeTag3 != typeTag1); + } + + //********************************* + TEST(test_type_tag_t) + { + using TypeTagType1 = etl::type_tag_t; + using TypeTagType2 = etl::type_tag_t; + using TypeTagType3 = etl::type_tag_t; + + CHECK_FALSE((std::is_same::value)); + CHECK_FALSE((std::is_same::value)); + CHECK_FALSE((std::is_same::value)); + } + + //********************************* + TEST(test_type_tag_underlying_t) + { + using TypeTagType1 = etl::type_tag_underlying_t; + using TypeTagType2 = etl::type_tag_underlying_t; + using TypeTagType3 = etl::type_tag_underlying_t; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } + + //********************************* +#if ETL_USING_CPP17 + TEST(test_type_tag_v) + { + constexpr auto typeTag1 = etl::type_tag_v; + constexpr auto typeTag2 = etl::type_tag_v; + constexpr auto typeTag3 = etl::type_tag_v; + + CHECK_TRUE(typeTag1 == typeTag1); + CHECK_TRUE(typeTag2 == typeTag2); + CHECK_TRUE(typeTag3 == typeTag3); + } +#endif }; }