Hello John,
Some time ago I asked whether further type traits would be included in boost. 
Unfortunately that somehow fizzled out.
Because based on this, many useful functions and classes can first be defined 
that behave correctly.
But the problems are much deeper and I would like to show a solution here.

1)
For some types there are feature-tesing-macros (e.g. __cpp_char8_t, 
__cpp_unicode_characters), but not for most. So this is incomplete. So we need 
this (plus the __cpp_lib-macros):
- __cpp_char8/16/32_t, __cpp charw_t, __cpp_char_t
- __cpp_int8/16/32/64/128_t
- __cpp_float16/32/64/80/128_t, __cpp_float16b_t
- __cpp_bool_t


2)
Building on this, we can then query, e.g.
struct has_float80: bool_constant
<
#if defined (__cpp_float80_t)
 true
#else
 false
#endif
> {};

template <typename Type>
struct is_float80: bool_constant
<
#if defined (__cpp_float80_t)
 is_same_v<Type, float80>
#else
 false
#endif
> {};

This has to be done for all types.


3)
Then we can further classify; plus is_X_v and concepts:

character:
template <typename Type>
struct is_character: bool_constant
<
#if defined (__cpp_char32_t)
 is_same_v<Type, char32_t> ||
#elif defined (__cpp_char16_t)
 is_same_v<Type, char16_t> ||
#elif defined (__cpp_char8_t)
 is_same_v<Type, char8_t> ||
#elif defined (__cpp_charw_t)
 is_same_v<Type, wchar_t> ||
#endif
 is_same_v<Type, char>
> {};

template <typename Type>
struct is_unsigned_character: bool_constant
<
 is_unsigned_v<Type> && character_v<Type>
> {};

template <typename Type>
is_signed_character: bool_constant
<
 is_signed_v<Type> && character_v<Type>
> {};


float:
template <typename Type>
struct is_floating_point: bool_constant
<
#if defined (__cpp_float128_t)
 is_same_v<Type, float128_t> ||
#elif defined (__cpp_float80_t)
 is_same_v<Type, float80_t> ||
#elif defined (__cpp_float64_t)
 is_same_v<Type, float64_t> ||
#elif defined (__cpp_float32_t)
 is_same_v<Type, float32_t> ||
#elif defined (__cpp_float16b_t)
 is_same_v<Type, float16b_t> ||
#elif defined (__cpp_float16_t)
 is_same_v<Type, float16_t> ||
#endif
 false
> {};


integer:
template <typename Type>
struct is_unsigned_integer: bool_constant
<
#if defined (__cpp_int128_t)
 is_same_v<Type, uint128_t> ||
#elif defined (__cpp_int64_t)
 is_same_v<Type, uint64_t> ||
#elif defined (__cpp_int32_t)
 is_same_v<Type, uint32_t> ||
#elif defined (__cpp_int16_t)
 is_same_v<Type, uint16_t> ||
#elif defined (__cpp_int8_t)
 is_same_v<Type, uint8_t> ||
#endif
 false
> {};

template <typename Type>
struct is_signed_integer: bool_constant
<
#if defined (__cpp_int128_t)
 is_same_v<Type, int128_t> ||
#elif defined (__cpp_int64_t)
 is_same_v<Type, int64_t> ||
#elif defined (__cpp_int32_t)
 is_same_v<Type, int32_t> ||
#elif defined (__cpp_int16_t)
 is_same_v<Type, int16_t> ||
#elif defined (__cpp_int8_t)
 is_same_v<Type, int8_t> ||
#endif
 false
> {};

template <typename Type>
struct is_integer: bool_constant
<
 is_unsigned_integer_v<Type> || is_signed_integer_v<Type>
> {};


logic:
template <typename Type>
struct is_logic: bool_constant
<
 is_same_v<Type, bool>
> {};

With that we would have created the basics to be able to continue working 
properly at all. 


4)
3 more steps to make things easier

#define bitsof(ARG) (size_t(sizeof(ARG) * CHAR_BIT))

Like std::numbers with std::strings with various constantans 
namespace strings
{
constexpr static auto empty = "";
constexpr static auto nullptr = "nullptr";
constexpr static auto Void = "void";

constexpr static auto True = "true";
constexpr static auto False = "false";
constexpr static auto indeterminate = "indeterminate";
constexpr static auto overdeterminate = "overdeterminate";
constexpr static auto underdeterminate = "underdeterminate";

constexpr static auto bin = "bin";
constexpr static auto oct = "oct";
constexpr static auto dec = "dec";
constexpr static auto hex = "hex";

constexpr static auto literal_bin = "0b";
constexpr static auto literal_oct = "0o";
constexpr static auto literal_dec = "0d";
constexpr static auto literal_hex = "0x";
}

and more

and for streams so that you don't have to fumble with the flags
namespace detail
{
using format_flags_t = typename std::ios_base::fmtflags;

static inline constexpr format_flags_t
        defaultfloat = format_flags_t{},
        hexfloat = std::ios_base::fixed | std::ios_base::scientific;

inline format_flags_t get_flags (const std::ios_base & stream, const 
format_flags_t & fieldmask) noexcept
{
        return stream.flags () & fieldmask;
}
} // detail

inline bool is_boolalpha (const std::ios_base & stream) noexcept {return 
(stream.flags () & stream.boolalpha) == stream.boolalpha; }
inline bool is_showbase (const std::ios_base & stream) noexcept {return 
(stream.flags () & stream.showbase) == stream.showbase; }
inline bool is_showpoint (const std::ios_base & stream) noexcept {return 
(stream.flags () & stream.showpoint) == stream.showpoint; }
inline bool is_skip (const std::ios_base & stream) noexcept {return 
(stream.flags () & stream.skipws) == stream.skipws; }
inline bool is_uppercase (const std::ios_base & stream) noexcept {return 
(stream.flags () & stream.uppercase) == stream.uppercase; }
inline bool is_lowercase (const std::ios_base & stream) noexcept {return! 
is_uppercase (stream); }

inline bool is_float_bin (const std::ios_base & stream) noexcept {return false; 
}
inline bool is_float_hex (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.floatfield) == detail::hexfloat; }
inline bool is_float_fixed (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.floatfield) == stream.fixed; }
inline bool is_float_default (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.floatfield) == detail::defaultfloat; }
inline bool is_float_scientific (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.floatfield) == stream.scientific; }

inline bool is_integer_bin (const std::ios_base & stream) noexcept {return 
false; }
inline bool is_integer_oct (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.basefield) == stream.oct; }
inline bool is_integer_dec (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.basefield) == stream.dec; }
inline bool is_integer_hex (const std::ios_base & stream) noexcept {return 
detail::get_flags (stream, stream.basefield) == stream.hex; }


5)
And now we can finally get correctly working functions, e.g.
template <integer Type, unsigned_integer Bits>
inline constexpr Type shl(const Type& arg, const Bits& bits) noexcept
{
        using unsigned_type = make_unsigned_t<Type>;
        const type
                res {Type(arg << unsigned_type(bits))};
        return (bits < bitsof(Type)) ? res : Type{0};
}

template <integer Type, unsigned_integer Bits>
inline constexpr Type shr(const Type& arg, const Bits& bits) noexcept
{
        using unsigned_type = make_unsigned_t<Type>;
        const type
                ovl {is_signed_integer_v<Type> ? ((arg < Type{0})? Type(-1) : 
Type{0}) : Type{0}},
                res {Type(arg >> unsigned_type(bits))};
        return (bits < bitsof(Type)) ? res : ovl;
}
and classes, e.g. constexpr bool2/3/4 with
template <> struct is_logic<bool4>: true_type {};
template <> struct is_logic<bool3>: true_type {};
template <> struct is_logic<bool2>: true_type {};
(I am happy to send it to you, because boost::tribool does not meet the 
requirements).

PS: I could have used the days multi-array/multi-index; but that's done because 
all of these libs are not constexpr. Will these be updated again?

thx
Gero

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
https://lists.boost.org/mailman/listinfo.cgi/boost-users

Reply via email to