diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-12-08 17:44:42 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-12-08 17:44:42 +0900 |
commit | 3489b77bba1b9429925dfe9539c2a9e8137fc622 (patch) | |
tree | 59a7cb3bc7b25eee12a37c43db4c069b7c240464 /lib/util.h | |
parent | 39204f0099e5556eb46bed00f3b31413af860a45 (diff) | |
parent | 5ea115d6eb0b60dfd0c2be5fbe5e69615b133238 (diff) | |
download | libquotient-3489b77bba1b9429925dfe9539c2a9e8137fc622.tar.gz libquotient-3489b77bba1b9429925dfe9539c2a9e8137fc622.zip |
Merge branch 'kitsune-tweaks-fixes'
Diffstat (limited to 'lib/util.h')
-rw-r--r-- | lib/util.h | 106 |
1 files changed, 73 insertions, 33 deletions
@@ -31,6 +31,8 @@ #define FALLTHROUGH [[fallthrough]] #elif __has_cpp_attribute(clang::fallthrough) #define FALLTHROUGH [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +#define FALLTHROUGH [[gnu::fallthrough]] #else #define FALLTHROUGH // -fallthrough #endif @@ -86,17 +88,19 @@ namespace QMatrixClient static_assert(!std::is_reference<T>::value, "You cannot make an Omittable<> with a reference type"); public: + using value_type = std::decay_t<T>; + explicit Omittable() : Omittable(none) { } - Omittable(NoneTag) : _value(std::decay_t<T>()), _omitted(true) { } - Omittable(const std::decay_t<T>& val) : _value(val) { } - Omittable(std::decay_t<T>&& val) : _value(std::move(val)) { } - Omittable<T>& operator=(const std::decay_t<T>& val) + Omittable(NoneTag) : _value(value_type()), _omitted(true) { } + Omittable(const value_type& val) : _value(val) { } + Omittable(value_type&& val) : _value(std::move(val)) { } + Omittable<T>& operator=(const value_type& val) { _value = val; _omitted = false; return *this; } - Omittable<T>& operator=(std::decay_t<T>&& val) + Omittable<T>& operator=(value_type&& val) { _value = std::move(val); _omitted = false; @@ -104,56 +108,92 @@ namespace QMatrixClient } bool omitted() const { return _omitted; } - const std::decay_t<T>& value() const { Q_ASSERT(!_omitted); return _value; } - std::decay_t<T>& value() { Q_ASSERT(!_omitted); return _value; } - std::decay_t<T>&& release() { _omitted = true; return std::move(_value); } + const value_type& value() const + { + Q_ASSERT(!_omitted); + return _value; + } + value_type& editValue() + { + _omitted = false; + return _value; + } + value_type&& release() { _omitted = true; return std::move(_value); } - operator bool() const { return !omitted(); } - const std::decay<T>* operator->() const { return &value(); } - std::decay_t<T>* operator->() { return &value(); } - const std::decay_t<T>& operator*() const { return value(); } - std::decay_t<T>& operator*() { return value(); } + operator value_type&() & { return editValue(); } + const value_type* operator->() const & { return &value(); } + value_type* operator->() & { return &editValue(); } + const value_type& operator*() const & { return value(); } + value_type& operator*() & { return editValue(); } private: T _value; bool _omitted = false; }; + namespace _impl { + template <typename AlwaysVoid, typename> struct fn_traits; + } + /** Determine traits of an arbitrary function/lambda/functor - * This only works with arity of 1 (1-argument) for now but is extendable - * to other cases. Also, doesn't work with generic lambdas and function - * objects that have operator() overloaded + * Doesn't work with generic lambdas and function objects that have + * operator() overloaded. * \sa https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765 */ template <typename T> - struct function_traits : public function_traits<decltype(&T::operator())> - { }; // A generic function object that has (non-overloaded) operator() + struct function_traits : public _impl::fn_traits<void, T> {}; // Specialisation for a function - template <typename ReturnT, typename ArgT> - struct function_traits<ReturnT(ArgT)> + template <typename ReturnT, typename... ArgTs> + struct function_traits<ReturnT(ArgTs...)> { + static constexpr auto is_callable = true; using return_type = ReturnT; - using arg_type = ArgT; + using arg_types = std::tuple<ArgTs..., void>; + static constexpr auto arg_number = std::tuple_size<arg_types>::value - 1; }; - // Specialisation for a member function - template <typename ReturnT, typename ClassT, typename ArgT> - struct function_traits<ReturnT(ClassT::*)(ArgT)> - : function_traits<ReturnT(ArgT)> - { }; + namespace _impl { + template <typename AlwaysVoid, typename T> + struct fn_traits + { + static constexpr auto is_callable = false; + }; - // Specialisation for a const member function - template <typename ReturnT, typename ClassT, typename ArgT> - struct function_traits<ReturnT(ClassT::*)(ArgT) const> - : function_traits<ReturnT(ArgT)> - { }; + template <typename T> + struct fn_traits<decltype(void(T::operator())), T> + : public fn_traits<void, decltype(T::operator())> + { }; // A generic function object that has (non-overloaded) operator() + + // Specialisation for a member function + template <typename ReturnT, typename ClassT, typename... ArgTs> + struct fn_traits<void, ReturnT(ClassT::*)(ArgTs...)> + : function_traits<ReturnT(ArgTs...)> + { }; + + // Specialisation for a const member function + template <typename ReturnT, typename ClassT, typename... ArgTs> + struct fn_traits<void, ReturnT(ClassT::*)(ArgTs...) const> + : function_traits<ReturnT(ArgTs...)> + { }; + } // namespace _impl template <typename FnT> using fn_return_t = typename function_traits<FnT>::return_type; - template <typename FnT> - using fn_arg_t = typename function_traits<FnT>::arg_type; + template <typename FnT, int ArgN = 0> + using fn_arg_t = + std::tuple_element_t<ArgN, typename function_traits<FnT>::arg_types>; + + template <typename R, typename FnT> + constexpr bool returns() + { + return std::is_same<fn_return_t<FnT>, R>::value; + } + + // Poor-man's is_invokable + template <typename T> + constexpr auto is_callable_v = function_traits<T>::is_callable; inline auto operator"" _ls(const char* s, std::size_t size) { |