Improve dereferenceMaybe()

* Support smart-pointers and other types which can
  be dereferenced
* Add tests
* Add documentation
This commit is contained in:
Marius Kittler 2018-07-10 13:17:04 +02:00
parent d029b33a19
commit 9743dc7d28
2 changed files with 76 additions and 5 deletions

View File

@ -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)) 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(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(IsReservable, std::declval<T &>().reserve(0u));
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsResizable, std::declval<T &>().resize(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* // operator*
void(*begin(std::declval<T &>()))); 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 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 auto &dereferenceMaybe(T &value)
{ {
return *x; 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 *value;
}
/// \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 value;
} }
} // namespace Traits } // namespace Traits

View File

@ -1,21 +1,28 @@
#include "../misc/traits.h" #include "../misc/traits.h"
#include "../tests/testutils.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <forward_list> #include <forward_list>
#include <list> #include <list>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
using namespace std; using namespace std;
using namespace Traits; using namespace Traits;
using namespace CPPUNIT_NS;
struct SomeStruct { struct SomeStruct {
string foo; string foo;
int bar; int bar;
}; };
struct CountableStruct { struct CountableStruct {
int numberOfElements; int numberOfElements = 42;
size_t size() const; 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<bool, string, int, bool>::value, "IsNoneOf: negative case");
static_assert(IsNoneOf<unsigned int, string, int, bool>::value, "IsNoneOf: positive 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<int>::value, "IsIterator: negative case");
static_assert(!IsIteratable<SomeStruct>::value, "IsIterator: negative case"); static_assert(!IsIteratable<SomeStruct>::value, "IsIterator: negative case");
static_assert(IsIteratable<string>::value, "IsIterator: positive 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<TestIncomplete>::value, "IsComplete: negative case");
static_assert(IsComplete<CountableStruct>::value, "IsComplete: positive 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));
}