diff options
Diffstat (limited to 'include/jsoncons/more_type_traits.hpp')
-rw-r--r-- | include/jsoncons/more_type_traits.hpp | 874 |
1 files changed, 874 insertions, 0 deletions
diff --git a/include/jsoncons/more_type_traits.hpp b/include/jsoncons/more_type_traits.hpp new file mode 100644 index 0000000..8e6b6c2 --- /dev/null +++ b/include/jsoncons/more_type_traits.hpp @@ -0,0 +1,874 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MORE_TYPE_TRAITS_HPP +#define JSONCONS_MORE_TYPE_TRAITS_HPP + +#include <stdexcept> +#include <string> +#include <cmath> +#include <type_traits> // std::enable_if, std::true_type +#include <memory> +#include <iterator> // std::iterator_traits +#include <exception> +#include <array> // std::array +#include <cstddef> // std::byte +#include <utility> // std::declval +#include <climits> // CHAR_BIT +#include <jsoncons/config/compiler_support.hpp> + +namespace jsoncons { +namespace type_traits { + + // is_char8 + template <typename CharT, typename Enable=void> + struct is_char8 : std::false_type {}; + + template <typename CharT> + struct is_char8<CharT, typename std::enable_if<std::is_integral<CharT>::value && + !std::is_same<CharT,bool>::value && + sizeof(uint8_t) == sizeof(CharT)>::type> : std::true_type {}; + + // is_char16 + template <typename CharT, typename Enable=void> + struct is_char16 : std::false_type {}; + + template <typename CharT> + struct is_char16<CharT, typename std::enable_if<std::is_integral<CharT>::value && + !std::is_same<CharT,bool>::value && + (std::is_same<CharT,char16_t>::value || sizeof(uint16_t) == sizeof(CharT))>::type> : std::true_type {}; + + // is_char32 + template <typename CharT, typename Enable=void> + struct is_char32 : std::false_type {}; + + template <typename CharT> + struct is_char32<CharT, typename std::enable_if<std::is_integral<CharT>::value && + !std::is_same<CharT,bool>::value && + (std::is_same<CharT,char32_t>::value || (!std::is_same<CharT,char16_t>::value && sizeof(uint32_t) == sizeof(CharT)))>::type> : std::true_type {}; + + // is_int128 + + template <class T, class Enable=void> + struct is_int128_type : std::false_type {}; + +#if defined(JSONCONS_HAS_INT128) + template <class T> + struct is_int128_type<T,typename std::enable_if<std::is_same<T,int128_type>::value>::type> : std::true_type {}; +#endif + + // is_unsigned_integer + + template <class T, class Enable=void> + struct is_uint128_type : std::false_type {}; + +#if defined (JSONCONS_HAS_INT128) + template <class T> + struct is_uint128_type<T,typename std::enable_if<std::is_same<T,uint128_type>::value>::type> : std::true_type {}; +#endif + + template <class T, class Enable = void> + class integer_limits + { + public: + static constexpr bool is_specialized = false; + }; + + template <class T> + class integer_limits<T,typename std::enable_if<std::is_integral<T>::value && !std::is_same<T,bool>::value>::type> + { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = std::numeric_limits<T>::is_signed; + static constexpr int digits = std::numeric_limits<T>::digits; + static constexpr std::size_t buffer_size = static_cast<std::size_t>(sizeof(T)*CHAR_BIT*0.302) + 3; + + static constexpr T(max)() noexcept + { + return (std::numeric_limits<T>::max)(); + } + static constexpr T(min)() noexcept + { + return (std::numeric_limits<T>::min)(); + } + static constexpr T lowest() noexcept + { + return std::numeric_limits<T>::lowest(); + } + }; + + template <class T> + class integer_limits<T,typename std::enable_if<!std::is_integral<T>::value && is_int128_type<T>::value>::type> + { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr int digits = sizeof(T)*CHAR_BIT - 1; + static constexpr std::size_t buffer_size = (sizeof(T)*CHAR_BIT*0.302) + 3; + + static constexpr T(max)() noexcept + { + return (((((T)1 << (digits - 1)) - 1) << 1) + 1); + } + static constexpr T(min)() noexcept + { + return -(max)() - 1; + } + static constexpr T lowest() noexcept + { + return (min)(); + } + }; + + template <class T> + class integer_limits<T,typename std::enable_if<!std::is_integral<T>::value && is_uint128_type<T>::value>::type> + { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr int digits = sizeof(T)*CHAR_BIT; + + static constexpr T(max)() noexcept + { + return T(T(~0)); + } + static constexpr T(min)() noexcept + { + return 0; + } + static constexpr T lowest() noexcept + { + return std::numeric_limits<T>::lowest(); + } + }; + + #ifndef JSONCONS_HAS_VOID_T + // follows https://en.cppreference.com/w/cpp/types/void_t + template<typename... Ts> struct make_void { typedef void type;}; + template<typename... Ts> using void_t = typename make_void<Ts...>::type; + #else + using void_t = std::void_t; + #endif + + // follows http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf + + // detector + + // primary template handles all types not supporting the archetypal Op + template< + class Default, + class, // always void; supplied externally + template<class...> class Op, + class... Args + > + struct detector + { + constexpr static auto value = false; + using type = Default; + }; + + // specialization recognizes and handles only types supporting Op + template< + class Default, + template<class...> class Op, + class... Args + > + struct detector<Default, void_t<Op<Args...>>, Op, Args...> + { + constexpr static auto value = true; + using type = Op<Args...>; + }; + + // is_detected, is_detected_t + + template< template<class...> class Op, class... Args > + using + is_detected = detector<void, void, Op, Args...>; + + template< template<class...> class Op, class... Args > + using + is_detected_t = typename is_detected<Op, Args...>::type; + + // detected_or, detected_or_t + + template< class Default, template<class...> class Op, class... Args > + using + detected_or = detector<Default, void, Op, Args...>; + + template< class Default, template<class...> class Op, class... Args > + using + detected_or_t = typename detected_or<Default, Op, Args...>::type; + + // is_detected_exact + + template< class Expected, template<class...> class Op, class... Args > + using + is_detected_exact = std::is_same< Expected, is_detected_t<Op, Args...> >; + + // is_detected_convertible + + template< class To, template<class...> class Op, class... Args > + using + is_detected_convertible = std::is_convertible< is_detected_t<Op, Args...>, To >; + + template <typename T> + struct is_stateless + : public std::integral_constant<bool, + (std::is_default_constructible<T>::value && + std::is_empty<T>::value)> + {}; + + // to_plain_pointer + + template<class Pointer> inline + typename std::pointer_traits<Pointer>::element_type* to_plain_pointer(Pointer ptr) + { + return (std::addressof(*ptr)); + } + + template<class T> inline + T * to_plain_pointer(T * ptr) + { + return (ptr); + } + + // is_std_byte + + template <class T, class Enable=void> + struct is_std_byte : std::false_type {}; +#if defined(JSONCONS_HAS_STD_BYTE) + template <class T> + struct is_std_byte<T, + typename std::enable_if<std::is_same<T,std::byte>::value + >::type> : std::true_type {}; +#endif + // is_byte + + template <class T, class Enable=void> + struct is_byte : std::false_type {}; + + template <class T> + struct is_byte<T, + typename std::enable_if<std::is_same<T,char>::value || + std::is_same<T,signed char>::value || + std::is_same<T,unsigned char>::value || + is_std_byte<T>::value + >::type> : std::true_type {}; + + // is_character + + template <class T, class Enable=void> + struct is_character : std::false_type {}; + + template <class T> + struct is_character<T, + typename std::enable_if<std::is_same<T,char>::value || + std::is_same<T,wchar_t>::value + >::type> : std::true_type {}; + + // is_narrow_character + + template <class T, class Enable=void> + struct is_narrow_character : std::false_type {}; + + template <class T> + struct is_narrow_character<T, + typename std::enable_if<is_character<T>::value && (sizeof(T) == sizeof(char)) + >::type> : std::true_type {}; + + // is_wide_character + + template <class T, class Enable=void> + struct is_wide_character : std::false_type {}; + + template <class T> + struct is_wide_character<T, + typename std::enable_if<is_character<T>::value && (sizeof(T) != sizeof(char)) + >::type> : std::true_type {}; + + // From boost + namespace ut_detail { + + template<typename T> + struct is_cstring_impl : public std::false_type {}; + + template<typename T> + struct is_cstring_impl<T const*> : public is_cstring_impl<T*> {}; + + template<typename T> + struct is_cstring_impl<T const* const> : public is_cstring_impl<T*> {}; + + template<> + struct is_cstring_impl<char*> : public std::true_type {}; + + template<> + struct is_cstring_impl<wchar_t*> : public std::true_type {}; + + } // namespace ut_detail + + template<typename T> + struct is_cstring : public ut_detail::is_cstring_impl<typename std::decay<T>::type> {}; + + // is_bool + + template <class T, class Enable=void> + struct is_bool : std::false_type {}; + + template <class T> + struct is_bool<T, + typename std::enable_if<std::is_same<T,bool>::value + >::type> : std::true_type {}; + + // is_u8_u16_u32_or_u64 + + template <class T, class Enable=void> + struct is_u8_u16_u32_or_u64 : std::false_type {}; + + template <class T> + struct is_u8_u16_u32_or_u64<T, + typename std::enable_if<std::is_same<T,uint8_t>::value || + std::is_same<T,uint16_t>::value || + std::is_same<T,uint32_t>::value || + std::is_same<T,uint64_t>::value + >::type> : std::true_type {}; + + // is_int + + template <class T, class Enable=void> + struct is_i8_i16_i32_or_i64 : std::false_type {}; + + template <class T> + struct is_i8_i16_i32_or_i64<T, + typename std::enable_if<std::is_same<T,int8_t>::value || + std::is_same<T,int16_t>::value || + std::is_same<T,int32_t>::value || + std::is_same<T,int64_t>::value + >::type> : std::true_type {}; + + // is_float_or_double + + template <class T, class Enable=void> + struct is_float_or_double : std::false_type {}; + + template <class T> + struct is_float_or_double<T, + typename std::enable_if<std::is_same<T,float>::value || + std::is_same<T,double>::value + >::type> : std::true_type {}; + + // make_unsigned + template <class T> + struct make_unsigned_impl {using type = typename std::make_unsigned<T>::type;}; + + #if defined(JSONCONS_HAS_INT128) + template <> + struct make_unsigned_impl<int128_type> {using type = uint128_type;}; + template <> + struct make_unsigned_impl<uint128_type> {using type = uint128_type;}; + #endif + + template <class T> + struct make_unsigned + : make_unsigned_impl<typename std::remove_cv<T>::type> + {}; + + // is_integer + + template <class T, class Enable=void> + struct is_integer : std::false_type {}; + + template <class T> + struct is_integer<T,typename std::enable_if<integer_limits<T>::is_specialized>::type> : std::true_type {}; + + // is_signed_integer + + template <class T, class Enable=void> + struct is_signed_integer : std::false_type {}; + + template <class T> + struct is_signed_integer<T, typename std::enable_if<integer_limits<T>::is_specialized && + integer_limits<T>::is_signed>::type> : std::true_type {}; + + // is_unsigned_integer + + template <class T, class Enable=void> + struct is_unsigned_integer : std::false_type {}; + + template <class T> + struct is_unsigned_integer<T, + typename std::enable_if<integer_limits<T>::is_specialized && + !integer_limits<T>::is_signed>::type> : std::true_type {}; + + // is_primitive + + template <class T, class Enable=void> + struct is_primitive : std::false_type {}; + + template <class T> + struct is_primitive<T, + typename std::enable_if<is_integer<T>::value || + is_bool<T>::value || + std::is_floating_point<T>::value + >::type> : std::true_type {}; + + // Containers + + template <class Container> + using + container_npos_t = decltype(Container::npos); + + template <class Container> + using + container_allocator_type_t = typename Container::allocator_type; + + template <class Container> + using + container_mapped_type_t = typename Container::mapped_type; + + template <class Container> + using + container_key_type_t = typename Container::key_type; + + template <class Container> + using + container_value_type_t = typename std::iterator_traits<typename Container::iterator>::value_type; + + template <class Container> + using + container_char_traits_t = typename Container::traits_type::char_type; + + template<class Container> + using + container_push_back_t = decltype(std::declval<Container>().push_back(std::declval<typename Container::value_type>())); + + template<class Container> + using + container_push_front_t = decltype(std::declval<Container>().push_front(std::declval<typename Container::value_type>())); + + template<class Container> + using + container_insert_t = decltype(std::declval<Container>().insert(std::declval<typename Container::value_type>())); + + template<class Container> + using + container_reserve_t = decltype(std::declval<Container>().reserve(typename Container::size_type())); + + template<class Container> + using + container_data_t = decltype(std::declval<Container>().data()); + + template<class Container> + using + container_size_t = decltype(std::declval<Container>().size()); + + // is_string_or_string_view + + template <class T, class Enable=void> + struct is_string_or_string_view : std::false_type {}; + + template <class T> + struct is_string_or_string_view<T, + typename std::enable_if<is_character<typename T::value_type>::value && + is_detected_exact<typename T::value_type,container_char_traits_t,T>::value && + is_detected<container_npos_t,T>::value + >::type> : std::true_type {}; + + // is_basic_string + + template <class T, class Enable=void> + struct is_basic_string : std::false_type {}; + + template <class T> + struct is_basic_string<T, + typename std::enable_if<is_string_or_string_view<T>::value && + is_detected<container_allocator_type_t,T>::value + >::type> : std::true_type {}; + + // is_basic_string_view + + template <class T, class Enable=void> + struct is_basic_string_view : std::false_type {}; + + template <class T> + struct is_basic_string_view<T, + typename std::enable_if<is_string_or_string_view<T>::value && + !is_detected<container_allocator_type_t,T>::value + >::type> : std::true_type {}; + + // is_map_like + + template <class T, class Enable=void> + struct is_map_like : std::false_type {}; + + template <class T> + struct is_map_like<T, + typename std::enable_if<is_detected<container_mapped_type_t,T>::value && + is_detected<container_allocator_type_t,T>::value && + is_detected<container_key_type_t,T>::value && + is_detected<container_value_type_t,T>::value + >::type> + : std::true_type {}; + + // is_std_array + template<class T> + struct is_std_array : std::false_type {}; + + template<class E, std::size_t N> + struct is_std_array<std::array<E, N>> : std::true_type {}; + + // is_list_like + + template <class T, class Enable=void> + struct is_list_like : std::false_type {}; + + template <class T> + struct is_list_like<T, + typename std::enable_if<is_detected<container_value_type_t,T>::value && + is_detected<container_allocator_type_t,T>::value && + !is_std_array<T>::value && + !is_detected_exact<typename T::value_type,container_char_traits_t,T>::value && + !is_map_like<T>::value + >::type> + : std::true_type {}; + + // is_constructible_from_const_pointer_and_size + + template <class T, class Enable=void> + struct is_constructible_from_const_pointer_and_size : std::false_type {}; + + template <class T> + struct is_constructible_from_const_pointer_and_size<T, + typename std::enable_if<std::is_constructible<T,typename T::const_pointer,typename T::size_type>::value + >::type> + : std::true_type {}; + + // has_reserve + + template<class Container> + using + has_reserve = is_detected<container_reserve_t, Container>; + + // is_back_insertable + + template<class Container> + using + is_back_insertable = is_detected<container_push_back_t, Container>; + + // is_front_insertable + + template<class Container> + using + is_front_insertable = is_detected<container_push_front_t, Container>; + + // is_insertable + + template<class Container> + using + is_insertable = is_detected<container_insert_t, Container>; + + // has_data, has_data_exact + + template<class Container> + using + has_data = is_detected<container_data_t, Container>; + + template<class Ret, class Container> + using + has_data_exact = is_detected_exact<Ret, container_data_t, Container>; + + // has_size + + template<class Container> + using + has_size = is_detected<container_size_t, Container>; + + // has_data_and_size + + template<class Container> + struct has_data_and_size + { + static constexpr bool value = has_data<Container>::value && has_size<Container>::value; + }; + + // is_byte_sequence + + template <class Container, class Enable=void> + struct is_byte_sequence : std::false_type {}; + + template <class Container> + struct is_byte_sequence<Container, + typename std::enable_if<has_data_exact<const typename Container::value_type*,const Container>::value && + has_size<Container>::value && + is_byte<typename Container::value_type>::value + >::type> : std::true_type {}; + + // is_char_sequence + + template <class Container, class Enable=void> + struct is_char_sequence : std::false_type {}; + + template <class Container> + struct is_char_sequence<Container, + typename std::enable_if<has_data_exact<const typename Container::value_type*,const Container>::value && + has_size<Container>::value && + is_character<typename Container::value_type>::value + >::type> : std::true_type {}; + + // is_sequence_of + + template <class Container, class ValueT, class Enable=void> + struct is_sequence_of : std::false_type {}; + + template <class Container, class ValueT> + struct is_sequence_of<Container,ValueT, + typename std::enable_if<has_data_exact<const typename Container::value_type*,const Container>::value && + has_size<Container>::value && + std::is_same<typename Container::value_type,ValueT>::value + >::type> : std::true_type {}; + + // is_back_insertable_byte_container + + template <class Container, class Enable=void> + struct is_back_insertable_byte_container : std::false_type {}; + + template <class Container> + struct is_back_insertable_byte_container<Container, + typename std::enable_if<is_back_insertable<Container>::value && + is_byte<typename Container::value_type>::value + >::type> : std::true_type {}; + + // is_back_insertable_char_container + + template <class Container, class Enable=void> + struct is_back_insertable_char_container : std::false_type {}; + + template <class Container> + struct is_back_insertable_char_container<Container, + typename std::enable_if<is_back_insertable<Container>::value && + is_character<typename Container::value_type>::value + >::type> : std::true_type {}; + + // is_back_insertable_container_of + + template <class Container, class ValueT, class Enable=void> + struct is_back_insertable_container_of : std::false_type {}; + + template <class Container, class ValueT> + struct is_back_insertable_container_of<Container, ValueT, + typename std::enable_if<is_back_insertable<Container>::value && + std::is_same<typename Container::value_type,ValueT>::value + >::type> : std::true_type {}; + + // is_c_array + + template<class T> + struct is_c_array : std::false_type {}; + + template<class T> + struct is_c_array<T[]> : std::true_type {}; + + template<class T, std::size_t N> + struct is_c_array<T[N]> : std::true_type {}; + +namespace impl { + + template<class C, class Enable=void> + struct is_typed_array : std::false_type {}; + + template<class T> + struct is_typed_array + < + T, + typename std::enable_if<is_list_like<T>::value && + (std::is_same<typename std::decay<typename T::value_type>::type,uint8_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,uint16_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,uint32_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,uint64_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,int8_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,int16_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,int32_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,int64_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,float_t>::value || + std::is_same<typename std::decay<typename T::value_type>::type,double_t>::value)>::type + > : std::true_type{}; + +} // namespace impl + + template <typename T> + using is_typed_array = impl::is_typed_array<typename std::decay<T>::type>; + + // is_compatible_element + + template<class Container, class Element, class Enable=void> + struct is_compatible_element : std::false_type {}; + + template<class Container, class Element> + struct is_compatible_element + < + Container, Element, + typename std::enable_if<has_data<Container>::value>::type> + : std::is_convertible< typename std::remove_pointer<decltype(std::declval<Container>().data() )>::type(*)[], Element(*)[]> + {}; + + template<typename T> + using + construct_from_string_t = decltype(T(std::string{})); + + + template<class T> + using + is_constructible_from_string = is_detected<construct_from_string_t,T>; + + template<typename T, typename Data, typename Size> + using + construct_from_data_size_t = decltype(T(static_cast<Data>(nullptr),Size{})); + + + template<class T, typename Data, typename Size> + using + is_constructible_from_data_size = is_detected<construct_from_data_size_t,T,Data,Size>; + + // is_unary_function_object + // is_unary_function_object_exact + + template<class FunctionObject, class Arg> + using + unary_function_object_t = decltype(std::declval<FunctionObject>()(std::declval<Arg>())); + + template<class FunctionObject, class Arg> + using + is_unary_function_object = is_detected<unary_function_object_t, FunctionObject, Arg>; + + template<class FunctionObject, class T, class Arg> + using + is_unary_function_object_exact = is_detected_exact<T,unary_function_object_t, FunctionObject, Arg>; + + // is_binary_function_object + // is_binary_function_object_exact + + template<class FunctionObject, class Arg1, class Arg2> + using + binary_function_object_t = decltype(std::declval<FunctionObject>()(std::declval<Arg1>(),std::declval<Arg2>())); + + template<class FunctionObject, class Arg1, class Arg2> + using + is_binary_function_object = is_detected<binary_function_object_t, FunctionObject, Arg1, Arg2>; + + template<class FunctionObject, class T, class Arg1, class Arg2> + using + is_binary_function_object_exact = is_detected_exact<T,binary_function_object_t, FunctionObject, Arg1, Arg2>; + + template <class Source, class Enable=void> + struct is_convertible_to_string_view : std::false_type {}; + + template <class Source> + struct is_convertible_to_string_view<Source,typename std::enable_if<is_string_or_string_view<Source>::value || + is_cstring<Source>::value + >::type> : std::true_type {}; + + #if defined(JSONCONS_HAS_2017) + template <typename T> + using is_nothrow_swappable = std::is_nothrow_swappable<T>; + #else + template <typename T> + struct is_nothrow_swappable { + static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>())); + }; + #endif + + #if defined(JSONCONS_HAS_2014) + template <class T> + using alignment_of = std::alignment_of<T>; + + template< class T, T... Ints > + using integer_sequence = std::integer_sequence<T,Ints...>; + + template <T ... Inds> + using index_sequence = std::index_sequence<Inds...>; + + template <class T, T N> + using make_integer_sequence = std::make_integer_sequence<T,N>; + + template <std::size_t N> + using make_index_sequence = std::make_index_sequence<N>; + + template<class... T> + using index_sequence_for = std::index_sequence_for<T...>; + + #else + template <class T> + struct alignment_of + : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {}; + + template <class T, T... Ints> + class integer_sequence + { + public: + using value_type = T; + static_assert(std::is_integral<value_type>::value, "not integral type"); + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } + }; + + template <std::size_t... Inds> + using index_sequence = integer_sequence<std::size_t, Inds...>; + namespace detail_ { + template <class T, T Begin, T End, bool> + struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral<TValue>::value, "not integral type"); + static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)"); + + template <class, class> + struct IntSeqCombiner; + + template <TValue... Inds0, TValue... Inds1> + struct IntSeqCombiner<integer_sequence<TValue, Inds0...>, integer_sequence<TValue, Inds1...>> { + using TResult = integer_sequence<TValue, Inds0..., Inds1...>; + }; + + using TResult = + typename IntSeqCombiner<typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2, + (End - Begin) / 2 == 1>::TResult, + typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End, + (End - Begin + 1) / 2 == 1>::TResult>::TResult; + }; + + template <class T, T Begin> + struct IntSeqImpl<T, Begin, Begin, false> { + using TValue = T; + static_assert(std::is_integral<TValue>::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence<TValue>; + }; + + template <class T, T Begin, T End> + struct IntSeqImpl<T, Begin, End, true> { + using TValue = T; + static_assert(std::is_integral<TValue>::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence<TValue, Begin>; + }; + } // namespace detail_ + + template <class T, T N> + using make_integer_sequence = typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult; + + template <std::size_t N> + using make_index_sequence = make_integer_sequence<std::size_t, N>; + + template <class... T> + using index_sequence_for = make_index_sequence<sizeof...(T)>; + + + #endif + +} // type_traits +} // jsoncons + +#endif |