diff --git a/README.md b/README.md index e09fad3..4d4a6b8 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,7 @@ Please use only sender OR receiver. ## Embedded Libraries - [ArxContainer v0.3.9](https://github.com/hideakitai/ArxContainer) +- [ArxTypeTraits v0.2.0](https://github.com/hideakitai/ArxTypeTraits) - [TeensyDirtySTLErrorSolution v0.1.0](https://github.com/hideakitai/TeensyDirtySTLErrorSolution) diff --git a/util/ArxTypeTraits/ArxTypeTraits.h b/util/ArxTypeTraits/ArxTypeTraits.h new file mode 100644 index 0000000..77b4d73 --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits.h @@ -0,0 +1,42 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_H +#define ARX_TYPE_TRAITS_H + +#if __cplusplus < 201103L + #error "C++11 must be enabled in the compiler for this library to work, please check your compiler flags" +#endif + +#include "ArxTypeTraits/has_include.h" +#include "ArxTypeTraits/has_libstdcplusplus.h" + +// Make sure std namespace exists +namespace std { } + +// Import everything from the std namespace into arx::std, so that +// anything we import rather than define is also available through +// arx::arx_std. +// This includes everything yet to be defined, so we can do this early +// (and must do so, to allow e.g. the C++14 additions in the arx::std +// namespace to reference the C++11 stuff from the system headers. +namespace arx { + namespace arx_std { + using namespace ::std; + } +} + +// Import everything from arx::std back into the normal std namespace. +// This ensures that you can just use `std::foo` everywhere and you get +// the standard library version if it is available, falling back to arx +// versions for things not supplied by the standard library. Only when +// you really need the arx version (e.g. for constexpr numeric_limits +// when also using ArduinoSTL), you need to qualify with arx::arx_std:: +namespace std { + using namespace ::arx::arx_std; +} + +#include "ArxTypeTraits/replace_minmax_macros.h" + +#include "ArxTypeTraits/type_traits.h" + +#endif // ARX_TYPE_TRAITS_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/functional.h b/util/ArxTypeTraits/ArxTypeTraits/functional.h new file mode 100644 index 0000000..06208de --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/functional.h @@ -0,0 +1,165 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_FUNCTIONAL_H +#define ARX_TYPE_TRAITS_FUNCTIONAL_H + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + +#include + +#else // Do not have libstdc++11 + +// If we have a header, include it and assume it has placement new +// (for AVR this has always been true, MEGAAVR does not have placement +// new now, but will probably get it before is added). +// This also handles the case where ArduinoSTL is used, which defines an +// inline placement new which would conflict with the below definition. +#if ARX_SYSTEM_HAS_INCLUDE() +#include +#else +// When there is no header, there might be a header, but +// not all Arduino platform (versions) define a placement new operator +// in there. +// However, it is hard to detect whether it is or is not defined, but +// the versions that do define it, do not define it inline in the +// header, so we can just define it inline here without conflicts. +// Note that there is no need to include anything to declare the +// non-placement new operators, since those are implicit. +inline void* operator new (const size_t size, void* ptr) noexcept { (void)size; return ptr; } +#endif + +namespace arx { namespace arx_std { + + // reference: + // stack overflow https://stackoverflow.com/questions/32074410/stdfunction-bind-like-type-erasure-without-standard-c-library + + template + class function; + + template + class function + { + struct vtable_t + { + void (*mover)(void* src, void* dest); + void (*destroyer)(void*); + R (*invoke)(void const* t, Args&&... args); + + template + static vtable_t const* get() + { + static const vtable_t table = + { + // mover + [] (void* src, void* dest) + { + new(dest) T(move(*static_cast(src))); + }, + // destroyer + [] (void* t) + { + static_cast(t)->~T(); + }, + // invoke + [] (void const* t, Args&&... args) -> R + { + return (*static_cast(t))(std::forward(args)...); + } + }; + return &table; + } + }; + + vtable_t const* table {nullptr}; + void* data {nullptr}; + + public: + + template < + class Func, + class dF = typename std::decay::type, + typename enable_if {}>::type* = nullptr, + typename enable_if ::type, R>{}>::type* = nullptr + > + function(const Func& f) + : table(vtable_t::template get()) + { + data = reinterpret_cast(new Func(f)); + } + function(const function& o) + : table(o.table) + { + data = o.data; + } + function(function&& o) + : table(o.table) + { + if (table) table->mover(o.data, data); + } + function() + { + } + ~function() + { + if (table) table->destroyer(data); + } + + function& operator= (const function& o) + { + this->~function(); + new(this) function(move(o)); + return *this; + } + function& operator= (function&& o) + { + this->~function(); + new(this) function(move(o)); + return *this; + } + function& operator= (std::nullptr_t p) + { + (void)p; + this->~function(); + return *this; + } + + explicit operator bool() const + { + return table; + } + + R operator()(Args...args) const + { + return table->invoke(data, forward(args)...); + } + }; + + template + inline bool operator== (const function& f, std::nullptr_t) + { + return !static_cast(f); + } + + template + inline bool operator== (std::nullptr_t, const function& f) + { + return !static_cast(f); + } + + template + inline bool operator!= (const function& f, std::nullptr_t) + { + return static_cast(f); + } + + template + inline bool operator!= (std::nullptr_t, const function& f) + { + return static_cast(f); + } + +} } // namespace arx::std + +#endif // Do not have libstdc++11 + +#endif // ARX_TYPE_TRAITS_FUNCTIONAL_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/has_include.h b/util/ArxTypeTraits/ArxTypeTraits/has_include.h new file mode 100644 index 0000000..76b39a9 --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/has_include.h @@ -0,0 +1,29 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_HAS_INCLUDE_H +#define ARX_TYPE_TRAITS_HAS_INCLUDE_H + + // Check whether __has_include is available, but also check the GCC + // version (__has_include was introduced in gcc 5) to catch + // environments (such as ESP8266) where gcc is old, but some system + // header provides a fake __has_include. We also need to check + // against __clang__ here, since clang pretends to be GCC + // 4.something and would otherwise be detected incorrectly here... + #if !defined(__has_include) || defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) + #if defined(ARDUINO_ARCH_ESP8266) + // ESP8266 does not have a working __has_include, but we + // know it does have a working libstdc++ with all the + // headers we care about, so provide a fake has_include + #define ARX_SYSTEM_HAS_INCLUDE(x) 1 + #elif defined(ARDUINO_SAM_DUE) + // Arduino DUE's GCC version is 4.8.3 (GCC < 5.0). + // And it has not libstdc++ + #define ARX_SYSTEM_HAS_INCLUDE(x) 0 + #else + #error "Compiler does not support __has_include, please report a bug against the ArxTypeTraits library about this." + #endif + #else + #define ARX_SYSTEM_HAS_INCLUDE(x) __has_include(x) + #endif + +#endif // ARX_TYPE_TRAITS_HAS_INCLUDE_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/has_libstdcplusplus.h b/util/ArxTypeTraits/ArxTypeTraits/has_libstdcplusplus.h new file mode 100644 index 0000000..77d77be --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/has_libstdcplusplus.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H +#define ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H + +#if !defined(ARX_HAVE_LIBSTDCPLUSPLUS) + #if ARX_SYSTEM_HAS_INCLUDE() + #include + #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) + // For gcc's libstdc++ and clang's libc++, assume that + // __cplusplus tells us what the standard includes support + #define ARX_HAVE_LIBSTDCPLUSPLUS __cplusplus + #elif defined(__UCLIBCXX_MAJOR__) + // For uclibc++, assume C++98 support only. + #define ARX_HAVE_LIBSTDCPLUSPLUS 199711L + #else + #error "Unknown C++ library found, please report a bug against the ArxTypeTraits library about this." + #endif + #else + // Assume no standard library is available at all (e.g. on AVR) + #define ARX_HAVE_LIBSTDCPLUSPLUS 0 + #endif +#endif + +#endif // ARX_TYPE_TRAITS_HAS_LIBSTDCPLUSPLUS_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/initializer_list.h b/util/ArxTypeTraits/ArxTypeTraits/initializer_list.h new file mode 100644 index 0000000..b1cd74f --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/initializer_list.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_INITIALIZER_H +#define ARX_TYPE_TRAITS_INITIALIZER_H + +// Initializer_list *must* be defined in std, so take extra care to only +// define it when is really not available (e.g. +// ArduinoSTL is C++98 but *does* define ) and not +// already defined (e.g. by ArxContainer). +#if ARX_SYSTEM_HAS_INCLUDE() +#include +#else +namespace std { + template + class initializer_list + { + private: + const T* array; + size_t len; + initializer_list(const T* a, size_t l) : array(a), len(l) {} + public: + initializer_list() : array(nullptr), len(0) {} + size_t size() const { return len; } + const T *begin() const { return array; } + const T *end() const { return array + len; } + }; +} // namespace std +#endif + +#endif // ARX_TYPE_TRAITS_INITIALIZER_LIST_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/replace_minmax_macros.h b/util/ArxTypeTraits/ArxTypeTraits/replace_minmax_macros.h new file mode 100644 index 0000000..9668ccc --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/replace_minmax_macros.h @@ -0,0 +1,33 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H +#define ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H + +// Make sure Arduino.h is actually included, since otherwise it might be +// included later and break *uses* of the min/max methods, rather than +// the declarations of it. +#include + +// These macros are defined by Arduino.h on some platforms, and conflict +// with min/max methods defined or included by ArxTypeTraits, so replace +// them with macros here. +#ifdef max + #undef max + template + constexpr auto max(T1 x, T2 y) + -> decltype(x + y) + { + return (x > y) ? x : y; + } +#endif +#ifdef min + #undef min + template + constexpr auto min(T1 x, T2 y) + -> decltype(x + y) + { + return (x < y) ? x : y; + } +#endif + +#endif // ARX_TYPE_TRAITS_REPLACE_MINMAX_MACROS_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/tuple.h b/util/ArxTypeTraits/ArxTypeTraits/tuple.h new file mode 100644 index 0000000..1489533 --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/tuple.h @@ -0,0 +1,82 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_TUPLE_H +#define ARX_TYPE_TRAITS_TUPLE_H + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + +#include + +#else // Do not have libstdc++11 + +namespace arx { namespace arx_std { + + // https://theolizer.com/cpp-school2/cpp-school2-15/ + // https://wandbox.org/permlink/C0BWIzjqg4iO3kKZ + + template + struct tuple + { + tuple() {} + }; + + template + class tuple : public tuple + { + template friend struct get_helper; + tFirst mMember; + public: + tuple(tFirst const& iFirst, tRest const&... iRest) + : tuple(iRest...) + , mMember(iFirst) + { } + constexpr tuple() {} + }; + + template + struct get_helper { }; + template + struct get_helper<0, tFirst, tRest...> + { + typedef tFirst type; + static type& get(tuple& iTuple) + { + return iTuple.mMember; + } + }; + template + struct get_helper + { + typedef typename get_helper::type type; + static type& get(tuple& iTuple) + { + return get_helper::get(iTuple); + } + }; + + template + typename get_helper::type& get(tuple& iTuple) + { + return get_helper::get(iTuple); + } + + template class tuple_size; + template class tuple_size; + template class tuple_size; + template class tuple_size; + template + class tuple_size > + : public integral_constant {}; + + template + auto make_tuple(Types&&... args) + -> std::tuple::type...> + { + return std::tuple::type...>(std::forward::type>(args)...); + } + +} } // namespace arx::std + +#endif // Do not have libstdc++11 + +#endif // ARX_TYPE_TRAITS_TUPLE_H diff --git a/util/ArxTypeTraits/ArxTypeTraits/type_traits.h b/util/ArxTypeTraits/ArxTypeTraits/type_traits.h new file mode 100644 index 0000000..7475830 --- /dev/null +++ b/util/ArxTypeTraits/ArxTypeTraits/type_traits.h @@ -0,0 +1,617 @@ +#pragma once + +#ifndef ARX_TYPE_TRAITS_TYPE_TRAITS_H +#define ARX_TYPE_TRAITS_TYPE_TRAITS_H + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 199711L // Have libstdc++98 + +#include + +#else // Do not have libstdc++98 + +namespace arx { namespace arx_std { + + template + void swap(T& a, T& b) + { + T t = move(a); + a = move(b); + b = move(t); + } +} } // namespace arx::arx_std + +#endif // Do not have libstdc++98 + + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 + +#include +#include + +#else // Do not have libstdc++11 + +#include +#include +#include + +namespace arx { namespace arx_std { + + using nullptr_t = decltype(nullptr); + + // numeric_limits + + template + struct numeric_limits + { + static constexpr T max() { return T(); } + static constexpr T min() { return T(); } + }; + template <> constexpr bool numeric_limits::max() { return true; } + template <> constexpr char numeric_limits::max() { return CHAR_MAX; } + template <> constexpr signed char numeric_limits::max() { return SCHAR_MAX; } + template <> constexpr unsigned char numeric_limits::max() { return UCHAR_MAX; } + template <> constexpr wchar_t numeric_limits::max() { return WCHAR_MAX; } + // template <> constexpr char8_t numeric_limits::max() { return UCHAR_MAX; } + template <> constexpr char16_t numeric_limits::max() { return UINT_LEAST16_MAX; } + template <> constexpr char32_t numeric_limits::max() { return UINT_LEAST32_MAX; } + template <> constexpr short numeric_limits::max() { return SHRT_MAX; } + template <> constexpr unsigned short numeric_limits::max() { return USHRT_MAX; } + template <> constexpr int numeric_limits::max() { return INT_MAX; } + template <> constexpr unsigned int numeric_limits::max() { return UINT_MAX; } + template <> constexpr long numeric_limits::max() { return LONG_MAX; } + template <> constexpr unsigned long numeric_limits::max() { return ULONG_MAX; } + // template <> constexpr long long numeric_limits::max() { return LLONG_MAX; } + // template <> constexpr unsigned long long numeric_limits::max() { return ULLONG_MAX; } + template <> constexpr float numeric_limits::max() { return FLT_MAX; } + template <> constexpr double numeric_limits::max() { return DBL_MAX; } + template <> constexpr long double numeric_limits::max() { return LDBL_MAX; } + + template <> constexpr bool numeric_limits::min() { return false; } + template <> constexpr char numeric_limits::min() { return CHAR_MIN; } + template <> constexpr signed char numeric_limits::min() { return SCHAR_MIN; } + template <> constexpr unsigned char numeric_limits::min() { return 0; } + template <> constexpr wchar_t numeric_limits::min() { return WCHAR_MIN; } + // template <> constexpr char8_t numeric_limits::min() { return 0; } + template <> constexpr char16_t numeric_limits::min() { return 0; } + template <> constexpr char32_t numeric_limits::min() { return 0; } + template <> constexpr short numeric_limits::min() { return SHRT_MIN; } + template <> constexpr unsigned short numeric_limits::min() { return 0; } + template <> constexpr int numeric_limits::min() { return INT_MIN; } + template <> constexpr unsigned int numeric_limits::min() { return 0; } + template <> constexpr long numeric_limits::min() { return LONG_MIN; } + template <> constexpr unsigned long numeric_limits::min() { return 0; } + // template <> constexpr long long numeric_limits::min() { return LLONG_MIN; } + // template <> constexpr unsigned long long numeric_limits::min() { return 0; } + template <> constexpr float numeric_limits::min() { return FLT_MIN; } + template <> constexpr double numeric_limits::min() { return DBL_MIN; } + template <> constexpr long double numeric_limits::min() { return LDBL_MIN; } + + + // integral_constant + + template + struct integral_constant + { + static constexpr T value = v; + using value_type = T; + using type = integral_constant; + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } + }; + + using true_type = integral_constant; + using false_type = integral_constant; + + + template + T declval(); // no implementation + + + template + struct enable_if; + template + struct enable_if { using type = T; }; + + + template + struct conditional { using type = T; }; + template + struct conditional { using type = F; }; + + + template struct remove_cv { using type = T; }; + template struct remove_cv { using type = T; }; + template struct remove_cv { using type = T; }; + template struct remove_cv { using type = T; }; + + template struct remove_const { using type = T; }; + template struct remove_const { using type = T; }; + + template struct remove_volatile { using type = T; }; + template struct remove_volatile { using type = T; }; + + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + template struct remove_pointer { using type = T; }; + + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + template struct remove_reference { using type = T; }; + + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + + + template + T&& move(T& t){ return static_cast(t); } + + + template + constexpr T&& forward(typename remove_reference::type& t) noexcept + { + return static_cast(t); + } + template + constexpr T&& forward(typename remove_reference::type&& t) noexcept + { + return static_cast(t); + } + + + namespace detail + { + template + struct type_identity { using type = T; }; + template + auto try_add_pointer(int) -> type_identity::type*>; + template + auto try_add_pointer(...) -> type_identity; + } + template + struct add_pointer : decltype(detail::try_add_pointer(0)) {}; + + + template + struct is_same : false_type {}; + template + struct is_same : true_type {}; + + + template + struct is_integral : false_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + + + template + struct is_floating_point : false_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + + + template + struct is_arithmetic + : conditional< + is_integral::value || is_floating_point::value, + true_type, + false_type + >::type + {}; + + + namespace detail + { + template ::value> + struct is_signed : integral_constant {}; + template + struct is_signed : false_type {}; + } + template + struct is_signed : detail::is_signed::type {}; + + + namespace detail + { + template::value> + struct is_unsigned : integral_constant {}; + template + struct is_unsigned : false_type {}; + } + template + struct is_unsigned : detail::is_unsigned::type {}; + + + template struct is_pointer_helper : false_type {}; + template struct is_pointer_helper : true_type {}; + template struct is_pointer : is_pointer_helper::type> {}; + + + template + struct is_array : false_type {}; + template + struct is_array : true_type {}; + template + struct is_array : true_type {}; + + + namespace details + { + template + struct Tester { using type = void; }; + template + using void_t = typename Tester::type; + templateclass Z, class, class...Ts> + struct can_apply : false_type{}; + templateclass Z, class...Ts> + struct can_apply>, Ts...> : true_type{}; + + template + using try_convert = decltype(To{declval()}); + } + templateclass Z, class...Ts> + using can_apply = details::can_apply; + + template + struct is_convertible + : conditional < + can_apply ::value + , true_type + , typename conditional < + is_arithmetic::value && is_arithmetic::value, + true_type, + false_type + >::type + >::type + {}; + + template<> + struct is_convertible : true_type{}; + + + // primary template + template + struct is_function : false_type { }; + // specialization for regular functions + template + struct is_function : true_type {}; + // specialization for variadic functions such as printf + template + struct is_function : true_type {}; + // specialization for function types that have cv-qualifiers + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + // specialization for function types that have ref-qualifiers + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + template + struct is_function : true_type {}; + + + template + struct is_empty : public integral_constant { }; + + + template + class decay + { + typedef typename remove_reference::type U; + public: + typedef typename conditional< + is_array::value, + typename remove_extent::type*, + typename conditional< + is_function::value, + typename add_pointer::type, + typename remove_cv::type + >::type + >::type type; + }; + + + namespace details + { + template struct tag { using type=T; }; + template using type_t = typename Tag::type; + + template + using invoke_t = decltype( declval()(declval()...) ); + + template + struct result_of {}; + template + struct result_of>> + : tag > + {}; + } + template + using result_of = details::result_of; + +} } // namespace arx::arx_std + +#endif // Do not have libstdc++11 + +#include "initializer_list.h" +#include "tuple.h" +#include "functional.h" + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201402L // Have libstdc++14 + // Nothing to include here, relevant header files were already included + // for C++11 above. +#else // Do not have libstdc++14 + +namespace arx { namespace arx_std { + + template + using enable_if_t = typename enable_if::type; + + template + using decay_t = typename decay::type; + + template + using remove_cv_t = typename remove_cv::type; + template + using remove_const_t = typename remove_const::type; + template + using remove_volatile_t = typename remove_volatile::type; + template + using remove_reference_t = typename remove_reference::type; + template + using remove_pointer_t = typename remove_pointer::type; + + template + struct integer_sequence + { + using type = integer_sequence; + using value_type = T; + static constexpr size_t size() noexcept { return sizeof...(Ts); } + }; + template + using index_sequence = integer_sequence; + + // https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence + + template + struct concat_impl; + template + using concat = typename concat_impl::type; + + template + struct concat_impl , index_sequence> + : index_sequence {}; + template + struct make_index_sequence_impl; + template + using make_index_sequence = typename make_index_sequence_impl::type; + template + struct make_index_sequence_impl + : concat, make_index_sequence > {}; + template<> + struct make_index_sequence_impl <0> : index_sequence<>{}; + template<> + struct make_index_sequence_impl <1> : index_sequence<0>{}; + + template + using index_sequence_for = make_index_sequence; + +} } // namespace arx::arx_std + +#endif // Do not have libstdc++14 + + +#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201703L // Have libstdc++17 + // Nothing to include here, relevant header files were already included + // for C++11 above. +#else // Do not have libstdc++17 + +namespace arx { namespace arx_std { + + template + struct Tester { using type = void; }; + template + using void_t = typename Tester::type; + + template + struct disjunction : false_type {}; + template + struct disjunction : Arg::type {}; + template + struct disjunction : conditional>::type {}; + + template + struct conjunction : true_type {}; + template + struct conjunction : Arg::type {}; + template + struct conjunction : conditional, Arg>::type {}; + + template + struct negation : integral_constant {}; + + // https://qiita.com/_EnumHack/items/92e6e135174f1f781dbb + // without decltype(auto) + + template + constexpr auto apply_impl(F&& f, Tuple&& t, index_sequence) + -> decltype(f(get(forward(t))...)) + { + return f(get(forward(t))...); + } + template + constexpr auto apply(F&& f, Tuple&& t) + -> decltype(apply_impl( + forward(f), + forward(t), + make_index_sequence>::value>{} + )) + { + return apply_impl( + forward(f), + forward(t), + make_index_sequence>::value>() + ); + } + +} } // namespace arx::arx_std + +#endif // Do not have libstdc++17 + + +#if ARX_HAVE_LIBSTDCPLUSPLUS > 201703L // Have libstdc++2a + // Nothing to include here, relevant header files were already included + // for C++11 above. +#else // Do not have libstdc++2a + +namespace arx { namespace arx_std { + + template + struct remove_cvref + { + typedef remove_cv_t> type; + }; + + template< class T > + using remove_cvref_t = typename remove_cvref::type; + +} } // namespace arx::arx_std +#endif // Do not have libstdc++2a + + +namespace arx { // others + + template class Check, class... T> + struct is_detected_impl : std::false_type {}; + template