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))
|
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
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue