Browse Source

Improve dereferenceMaybe()

* Support smart-pointers and other types which can
  be dereferenced
* Add tests
* Add documentation
sendfile
Marius Kittler 4 years ago
parent
commit
9743dc7d28
  1. 25
      misc/traits.h
  2. 56
      tests/traitstests.cpp

25
misc/traits.h

@ -94,6 +94,9 @@ template <typename T> struct IsComplete<T, decltype(void(sizeof(T)))> : Bool<tru
} \
template <typename T> using CheckName = decltype(Detail::CheckName<T>(0))
/// \brief Evaluates to Bool<true> if the specified type can be dereferenced using the *-operator; otherwise evaluates to Bool<false>.
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsDereferencable, *(std::declval<T &>()));
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(HasSize, std::is_integral<decltype(std::declval<T &>().size())>::value);
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsReservable, std::declval<T &>().reserve(0u));
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsResizable, std::declval<T &>().resize(0u));
@ -108,14 +111,28 @@ CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsIteratable,
// operator*
void(*begin(std::declval<T &>())));
template <typename T> T &dereferenceMaybe(T &x)
/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself.
template <typename T, EnableIf<IsDereferencable<T>> * = nullptr> constexpr auto &dereferenceMaybe(T &value)
{
return *value;
}
/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself.
template <typename T, DisableIf<IsDereferencable<T>> * = nullptr> constexpr auto &dereferenceMaybe(T &value)
{
return value;
}
/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself.
template <typename T, EnableIf<IsDereferencable<T>> * = nullptr> constexpr const auto &dereferenceMaybe(const T &value)
{
return x;
return *value;
}
template <typename T> T &dereferenceMaybe(T *x)
/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself.
template <typename T, DisableIf<IsDereferencable<T>> * = nullptr> constexpr const auto &dereferenceMaybe(const T &value)
{
return *x;
return value;
}
} // namespace Traits

56
tests/traitstests.cpp

@ -1,21 +1,28 @@
#include "../misc/traits.h"
#include "../tests/testutils.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <forward_list>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>
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<int, string, int, bool>::value, "IsNoneOf: negative case
static_assert(!IsNoneOf<bool, string, int, bool>::value, "IsNoneOf: negative case");
static_assert(IsNoneOf<unsigned int, string, int, bool>::value, "IsNoneOf: positive case");
static_assert(!IsDereferencable<string>::value, "IsDereferencable: negative case");
static_assert(!IsDereferencable<int>::value, "IsDereferencable: negative case");
static_assert(IsDereferencable<string *>::value, "IsDereferencable: positive case");
static_assert(IsDereferencable<int *>::value, "IsDereferencable: positive case");
static_assert(IsDereferencable<unique_ptr<string>>::value, "IsDereferencable: positive case");
static_assert(IsDereferencable<shared_ptr<string>>::value, "IsDereferencable: positive case");
static_assert(!IsDereferencable<weak_ptr<string>>::value, "IsDereferencable: positive case");
static_assert(!IsIteratable<int>::value, "IsIterator: negative case");
static_assert(!IsIteratable<SomeStruct>::value, "IsIterator: negative case");
static_assert(IsIteratable<string>::value, "IsIterator: positive case");
@ -78,3 +93,42 @@ static_assert(IsString<u16string>::value, "IsCString: positive case");
static_assert(!IsComplete<TestIncomplete>::value, "IsComplete: negative case");
static_assert(IsComplete<CountableStruct>::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<string>("foo");
CPPUNIT_ASSERT_EQUAL("foo"s, dereferenceMaybe(someString));
CPPUNIT_ASSERT_EQUAL("foo"s, dereferenceMaybe(someSmartPointer));
}

Loading…
Cancel
Save