2016-11-13 22:51:09 +01:00
|
|
|
#ifndef CPP_UTILITIES_TRAITS_H
|
|
|
|
#define CPP_UTILITIES_TRAITS_H
|
|
|
|
|
2017-05-08 19:51:24 +02:00
|
|
|
#include <iterator>
|
2020-01-01 16:38:04 +01:00
|
|
|
#include <string>
|
2016-11-13 22:51:09 +01:00
|
|
|
#include <type_traits>
|
|
|
|
|
2019-06-10 21:56:46 +02:00
|
|
|
namespace CppUtilities {
|
|
|
|
|
2017-02-03 00:54:44 +01:00
|
|
|
/// \brief Contains traits for conveniently exploiting SFINAE.
|
2016-11-13 22:51:09 +01:00
|
|
|
namespace Traits {
|
|
|
|
|
2017-02-03 00:54:44 +01:00
|
|
|
/// \cond
|
2016-11-13 22:51:09 +01:00
|
|
|
namespace Detail {
|
2017-05-01 03:13:11 +02:00
|
|
|
enum class Enabler {};
|
2016-11-13 22:51:09 +01:00
|
|
|
}
|
2017-02-03 00:54:44 +01:00
|
|
|
/// \endcond
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Shortcut for std::conditional to omit ::value and ::type.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename If, typename Then, typename Else> using Conditional = typename std::conditional<If::value, Then, Else>::type;
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Wraps a static boolean constant.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <bool B, typename...> struct Bool : std::integral_constant<bool, B> {
|
|
|
|
};
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Negates the specified value.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename T> using Not = Bool<!T::value>;
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if at least one of the specified conditions is true; otherwise evaluates to Bool<false>.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename... T> struct Any : Bool<false> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if at least one of the specified conditions is true; otherwise evaluates to Bool<false>.
|
2017-05-04 22:44:00 +02:00
|
|
|
template <typename Head, typename... Tail> struct Any<Head, Tail...> : Conditional<Head, Bool<true>, Any<Tail...>> {
|
2017-05-01 03:13:11 +02:00
|
|
|
};
|
2017-01-27 18:49:53 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if all specified conditions are true; otherwise evaluates to Bool<false>.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename... T> struct All : Bool<true> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if all specified conditions are true; otherwise evaluates to Bool<false>.
|
2017-05-04 22:44:00 +02:00
|
|
|
template <typename Head, typename... Tail> struct All<Head, Tail...> : Conditional<Head, All<Tail...>, Bool<false>> {
|
2017-05-01 03:13:11 +02:00
|
|
|
};
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if none of the specified conditions are true; otherwise evaluates to Bool<false>.
|
2018-06-23 14:33:00 +02:00
|
|
|
template <typename... T> struct None : Bool<true> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if none of the specified conditions are true; otherwise evaluates to Bool<false>.
|
2018-06-23 14:33:00 +02:00
|
|
|
template <typename Head, typename... Tail> struct None<Head, Tail...> : Conditional<Head, Bool<false>, None<Tail...>> {
|
|
|
|
};
|
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Shortcut for std::enable_if to omit ::value and ::type.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename... Condition> using EnableIf = typename std::enable_if<All<Condition...>::value, Detail::Enabler>::type;
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Shortcut for std::enable_if to negate the condition and omit ::value and ::type.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename... Condition> using DisableIf = typename std::enable_if<!All<Condition...>::value, Detail::Enabler>::type;
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Shortcut for std::enable_if to apply Traits::Any and omit ::value and ::type.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename... Condition> using EnableIfAny = typename std::enable_if<Any<Condition...>::value, Detail::Enabler>::type;
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Shortcut for std::enable_if to apply Traits::Any, negate the condition and omit ::value and ::type.
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename... Condition> using DisableIfAny = typename std::enable_if<!Any<Condition...>::value, Detail::Enabler>::type;
|
2017-01-30 00:08:35 +01:00
|
|
|
|
2018-10-29 23:16:16 +01:00
|
|
|
/// \cond
|
|
|
|
namespace Detail {
|
|
|
|
template <typename T, template <typename...> class Template> struct IsSpecializationOfHelper : Bool<false> {
|
2017-05-01 03:13:11 +02:00
|
|
|
};
|
2018-10-29 23:16:16 +01:00
|
|
|
template <template <typename...> class Template, typename... Args> struct IsSpecializationOfHelper<Template<Args...>, Template> : Bool<true> {
|
|
|
|
};
|
|
|
|
} // namespace Detail
|
|
|
|
/// \endcond
|
2020-06-17 21:41:00 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is based on the specified template; otherwise evaluates to Bool<false>.
|
2018-10-29 23:16:16 +01:00
|
|
|
template <typename Type, template <typename...> class... TemplateTypes>
|
2020-06-17 21:41:00 +02:00
|
|
|
struct IsSpecializationOf
|
|
|
|
: Detail::IsSpecializationOfHelper<typename std::remove_cv<typename std::remove_reference<Type>::type>::type, TemplateTypes...> {
|
2017-05-01 03:13:11 +02:00
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is based on one of the specified templates; otherwise evaluates to Bool<false>.
|
2018-06-24 20:06:01 +02:00
|
|
|
template <typename Type, template <typename...> class... TemplateTypes> struct IsSpecializingAnyOf : Bool<false> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is based on one of the specified templates; otherwise evaluates to Bool<false>.
|
2018-06-24 20:06:01 +02:00
|
|
|
template <typename Type, template <typename...> class TemplateType, template <typename...> class... RemainingTemplateTypes>
|
|
|
|
struct IsSpecializingAnyOf<Type, TemplateType, RemainingTemplateTypes...>
|
|
|
|
: Conditional<IsSpecializationOf<Type, TemplateType>, Bool<true>, IsSpecializingAnyOf<Type, RemainingTemplateTypes...>> {
|
|
|
|
};
|
2017-05-08 19:51:24 +02:00
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is any of the specified types; otherwise evaluates to Bool<false>.
|
2018-06-20 22:53:48 +02:00
|
|
|
template <typename... T> struct IsAnyOf : Bool<false> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is any of the specified types; otherwise evaluates to Bool<false>.
|
2018-06-20 22:53:48 +02:00
|
|
|
template <typename Type, typename OtherType, typename... RemainingTypes>
|
|
|
|
struct IsAnyOf<Type, OtherType, RemainingTypes...> : Conditional<std::is_same<Type, OtherType>, Bool<true>, IsAnyOf<Type, RemainingTypes...>> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is none of the specified types; otherwise evaluates to Bool<false>.
|
2018-06-20 22:53:48 +02:00
|
|
|
template <typename... T> struct IsNoneOf : Bool<true> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is none of the specified types; otherwise evaluates to Bool<false>.
|
2018-06-20 22:53:48 +02:00
|
|
|
template <typename Type, typename OtherType, typename... RemainingTypes>
|
|
|
|
struct IsNoneOf<Type, OtherType, RemainingTypes...> : Conditional<std::is_same<Type, OtherType>, Bool<false>, IsNoneOf<Type, RemainingTypes...>> {
|
|
|
|
};
|
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is a C-string (char * or const char *); otherwise evaluates to Bool<false>.
|
2017-05-10 23:31:28 +02:00
|
|
|
template <typename T>
|
|
|
|
struct IsCString
|
|
|
|
: Bool<std::is_same<char const *, typename std::decay<T>::type>::value || std::is_same<char *, typename std::decay<T>::type>::value> {
|
|
|
|
};
|
2019-11-28 21:32:41 +01:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is a standard string, standard string view or C-string (char * or const char *); otherwise
|
|
|
|
/// evaluates to Bool<false>.
|
|
|
|
template <typename T>
|
|
|
|
struct IsString
|
|
|
|
: Bool<IsCString<T>::value || IsSpecializationOf<T, std::basic_string>::value || IsSpecializationOf<T, std::basic_string_view>::value> {
|
2017-05-10 23:31:28 +02:00
|
|
|
};
|
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is complete; if the type is only forward-declared it evaluates to Bool<false>.
|
2017-11-16 02:00:03 +01:00
|
|
|
template <typename T, typename = void> struct IsComplete : Bool<false> {
|
|
|
|
};
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is complete; if the type is only forward-declared it evaluates to Bool<false>.
|
2017-11-16 02:00:03 +01:00
|
|
|
template <typename T> struct IsComplete<T, decltype(void(sizeof(T)))> : Bool<true> {
|
|
|
|
};
|
|
|
|
|
2017-11-01 15:19:28 +01:00
|
|
|
/*!
|
|
|
|
* \def CPP_UTILITIES_PP_COMMA
|
|
|
|
* \brief The CPP_UTILITIES_PP_COMMA macro helps passing "," as a macro argument.
|
|
|
|
*/
|
|
|
|
#define CPP_UTILITIES_PP_COMMA ,
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \def CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK
|
|
|
|
* \brief The CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK macro defines a type trait for checking whether some operation can be done with
|
|
|
|
* a particular type.
|
|
|
|
* \sa Traits::HasSize or Traits::IsIteratable for an example how to use it.
|
|
|
|
*/
|
|
|
|
#define CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(CheckName, CheckCode) \
|
|
|
|
namespace Detail { \
|
2019-06-10 21:56:46 +02:00
|
|
|
template <typename T> auto CheckName(int) -> decltype(CheckCode, ::CppUtilities::Traits::Bool<true>{}); \
|
|
|
|
template <typename T>::CppUtilities::Traits::Bool<false> CheckName(...); \
|
2017-11-01 15:19:28 +01:00
|
|
|
} \
|
|
|
|
template <typename T> using CheckName = decltype(Detail::CheckName<T>(0))
|
|
|
|
|
2018-07-10 13:17:04 +02:00
|
|
|
/// \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 &>()));
|
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type can has a size() method; otherwise evaluates to Bool<false>.
|
2017-11-01 15:19:28 +01:00
|
|
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(HasSize, std::is_integral<decltype(std::declval<T &>().size())>::value);
|
2018-07-10 13:17:26 +02:00
|
|
|
|
|
|
|
/// \brief Evaluates to Bool<true> if the specified type can has a reserve() method; otherwise evaluates to Bool<false>.
|
2017-11-01 15:19:28 +01:00
|
|
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsReservable, std::declval<T &>().reserve(0u));
|
2018-07-10 13:17:26 +02:00
|
|
|
|
|
|
|
/// \brief Evaluates to Bool<true> if the specified type can has a resize() method; otherwise evaluates to Bool<false>.
|
2018-06-20 22:55:18 +02:00
|
|
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsResizable, std::declval<T &>().resize(0u));
|
2018-07-10 13:17:26 +02:00
|
|
|
|
2018-10-21 20:21:28 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type has operator bool(); otherwise evaluates to Bool<false>.
|
|
|
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(HasOperatorBool, std::declval<T &>() ? true : false);
|
|
|
|
|
2018-07-10 13:17:26 +02:00
|
|
|
/// \brief Evaluates to Bool<true> if the specified type is iteratable (can be used in for-each loop); otherwise evaluates to Bool<false>.
|
2017-11-01 15:19:28 +01:00
|
|
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsIteratable,
|
2017-05-08 19:51:24 +02:00
|
|
|
// begin/end and operator !=
|
2017-11-01 15:19:28 +01:00
|
|
|
std::begin(std::declval<T &>())
|
|
|
|
!= std::end(std::declval<T &>()) CPP_UTILITIES_PP_COMMA
|
|
|
|
// operator ,
|
|
|
|
void() CPP_UTILITIES_PP_COMMA
|
|
|
|
// operator ++
|
|
|
|
++ std::declval<decltype(begin(std::declval<T &>())) &>() CPP_UTILITIES_PP_COMMA
|
|
|
|
// operator*
|
|
|
|
void(*begin(std::declval<T &>())));
|
2017-10-27 16:31:29 +02:00
|
|
|
|
2018-07-10 13:17:04 +02:00
|
|
|
/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself.
|
2020-02-18 19:20:24 +01:00
|
|
|
template <typename T, EnableIf<IsDereferencable<T>> * = nullptr> constexpr auto &dereferenceMaybe(T &&value)
|
2018-07-10 13:17:04 +02:00
|
|
|
{
|
|
|
|
return *value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Dereferences the specified \a value if possible; otherwise just returns \a value itself.
|
2020-02-18 19:20:24 +01:00
|
|
|
template <typename T, DisableIf<IsDereferencable<T>> * = nullptr> constexpr auto &dereferenceMaybe(T &&value)
|
2018-07-01 23:22:33 +02:00
|
|
|
{
|
2018-07-10 13:17:04 +02:00
|
|
|
return value;
|
2018-07-01 23:22:33 +02:00
|
|
|
}
|
|
|
|
|
2017-09-17 21:45:23 +02:00
|
|
|
} // namespace Traits
|
2016-11-13 22:51:09 +01:00
|
|
|
|
2019-06-10 21:56:46 +02:00
|
|
|
} // namespace CppUtilities
|
|
|
|
|
2016-11-13 22:51:09 +01:00
|
|
|
#endif // CPP_UTILITIES_TRAITS_H
|