Improve dereferenceMaybe()
* Support smart-pointers and other types which can be dereferenced * Add tests * Add documentation
This commit is contained in:
parent
d029b33a19
commit
9743dc7d28
|
@ -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 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
|
||||
|
|
|
@ -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…
Reference in New Issue