diff --git a/misc/traits.h b/misc/traits.h index c17ea70..3135c42 100644 --- a/misc/traits.h +++ b/misc/traits.h @@ -94,6 +94,9 @@ template struct IsComplete : Bool using CheckName = decltype(Detail::CheckName(0)) +/// \brief Evaluates to Bool if the specified type can be dereferenced using the *-operator; otherwise evaluates to Bool. +CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsDereferencable, *(std::declval())); + CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(HasSize, std::is_integral().size())>::value); CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsReservable, std::declval().reserve(0u)); CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsResizable, std::declval().resize(0u)); @@ -108,14 +111,28 @@ CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsIteratable, // operator* void(*begin(std::declval()))); -template T &dereferenceMaybe(T &x) +/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself. +template > * = nullptr> constexpr auto &dereferenceMaybe(T &value) { - return x; + return *value; } -template T &dereferenceMaybe(T *x) +/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself. +template > * = nullptr> constexpr auto &dereferenceMaybe(T &value) { - return *x; + return value; +} + +/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself. +template > * = nullptr> constexpr const auto &dereferenceMaybe(const T &value) +{ + return *value; +} + +/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself. +template > * = nullptr> constexpr const auto &dereferenceMaybe(const T &value) +{ + return value; } } // namespace Traits diff --git a/tests/traitstests.cpp b/tests/traitstests.cpp index 92c4bc3..a3f02cb 100644 --- a/tests/traitstests.cpp +++ b/tests/traitstests.cpp @@ -1,21 +1,28 @@ #include "../misc/traits.h" +#include "../tests/testutils.h" + +#include +#include #include #include #include +#include #include #include using namespace std; using namespace Traits; +using namespace CPPUNIT_NS; + struct SomeStruct { string foo; int bar; }; struct CountableStruct { - int numberOfElements; + int numberOfElements = 42; size_t size() const; }; @@ -49,6 +56,14 @@ static_assert(!IsNoneOf::value, "IsNoneOf: negative case static_assert(!IsNoneOf::value, "IsNoneOf: negative case"); static_assert(IsNoneOf::value, "IsNoneOf: positive case"); +static_assert(!IsDereferencable::value, "IsDereferencable: negative case"); +static_assert(!IsDereferencable::value, "IsDereferencable: negative case"); +static_assert(IsDereferencable::value, "IsDereferencable: positive case"); +static_assert(IsDereferencable::value, "IsDereferencable: positive case"); +static_assert(IsDereferencable>::value, "IsDereferencable: positive case"); +static_assert(IsDereferencable>::value, "IsDereferencable: positive case"); +static_assert(!IsDereferencable>::value, "IsDereferencable: positive case"); + static_assert(!IsIteratable::value, "IsIterator: negative case"); static_assert(!IsIteratable::value, "IsIterator: negative case"); static_assert(IsIteratable::value, "IsIterator: positive case"); @@ -78,3 +93,42 @@ static_assert(IsString::value, "IsCString: positive case"); static_assert(!IsComplete::value, "IsComplete: negative case"); static_assert(IsComplete::value, "IsComplete: positive case"); + +constexpr int i = 5; +constexpr CountableStruct someStruct{}; +static_assert(dereferenceMaybe(&i) == 5, "int* dereferenced"); +static_assert(dereferenceMaybe(i) == 5, "int not dereferenced"); +static_assert(dereferenceMaybe(&someStruct).numberOfElements == 42, "CountableStruct* dereferenced"); +static_assert(dereferenceMaybe(someStruct).numberOfElements == 42, "CountableStruct not dereferenced"); + +/*! + * \brief The TraitsTest class tests parts of the Traits namespace which can not be evaluated at compile-time. + */ +class TraitsTest : public TestFixture { + CPPUNIT_TEST_SUITE(TraitsTest); + CPPUNIT_TEST(testDereferenceMaybe); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp() + { + } + void tearDown() + { + } + + void testDereferenceMaybe(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TraitsTest); + +/*! + * \brief Tests whether a smart pointer to a string can be treated like a normal string through the use of dereferenceMaybe(). + */ +void TraitsTest::testDereferenceMaybe() +{ + const auto someString = "foo"s; + const auto someSmartPointer = make_unique("foo"); + CPPUNIT_ASSERT_EQUAL("foo"s, dereferenceMaybe(someString)); + CPPUNIT_ASSERT_EQUAL("foo"s, dereferenceMaybe(someSmartPointer)); +}