Skip to content

Commit fa92d4a

Browse files
committed
Allow fmt::format for strong::ostreamable again
Constrain formatters to only types that are formattable or ostreamable
1 parent 3f9478e commit fa92d4a

File tree

3 files changed

+75
-39
lines changed

3 files changed

+75
-39
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Fixed issue #22, a regression with strong::formattable and fmtlib.
2+
A type that is strong::ostreamable con be formatted with fmt. A
3+
type that is both strong::formattable and strong::ostreamable will
4+
use the types formatter<> when using fmt. The behaviour of std::format
5+
is unchanged.
6+
17
* strong::arithmetic no longer specializes std::is_arithmetic<>. Issue
28
#19. This is expressively disallowed by the stdandard and is undefined
39
behaviour. Sorry for this potentially breaking change, but it was

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ can thus be used as key in `std::map`<> or `std::set<>`.
152152
`STRONG_HAS_FMT_FORMAT`. With 0 to disable the support completly, and with 1 to
153153
force the support, disable the auto detection.
154154
155+
`fmt::format` allows formatting also types that are `strong::ostreamable`.
156+
155157
For modifier `strong::iterator`, the type trait `std::iterator_traits` mirrors
156158
the traits of the underlying iterator type.
157159

include/strong_type/strong_type.hpp

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,9 @@ struct unique
483483
public:
484484
constexpr modifier() = default;
485485
modifier(const modifier&) = delete;
486-
constexpr modifier(modifier&&) = default;
486+
constexpr modifier(modifier&&) noexcept = default;
487487
modifier& operator=(const modifier&) = delete;
488-
constexpr modifier& operator=(modifier&&) = default;
488+
constexpr modifier& operator=(modifier&&) noexcept = default;
489489
};
490490
};
491491
struct ordered
@@ -1595,10 +1595,13 @@ struct implicitly_convertible_to
15951595

15961596
struct formattable
15971597
{
1598-
template <typename T>
1599-
class modifier{};
1598+
template <typename T>
1599+
class modifier{};
16001600
};
16011601

1602+
template <typename T>
1603+
using is_formattable = std::is_base_of<formattable::modifier<T>, T>;
1604+
16021605
}
16031606

16041607
namespace std {
@@ -1628,58 +1631,83 @@ struct hash<::strong::type<T, Tag, M...>>
16281631

16291632
#if STRONG_HAS_STD_FORMAT
16301633
template<typename T, typename Tag, typename... M, typename Char>
1631-
struct formatter<::strong::type<T, Tag, M...>, Char>
1632-
: std::enable_if_t<
1633-
std::is_base_of<
1634-
::strong::formattable::modifier<
1635-
::strong::type<T, Tag, M...>
1636-
>,
1637-
::strong::type<T, Tag, M...>
1638-
>::value,
1639-
formatter<T>
1640-
>
1634+
requires std::is_base_of_v<::strong::formattable::modifier<::strong::type<T, Tag, M...>>,
1635+
::strong::type<T, Tag, M...>>
1636+
struct formatter<::strong::type<T, Tag, M...>, Char> : formatter<T, Char>
16411637
{
1642-
using type = ::strong::type<T, Tag, M...>;
1643-
template<typename FormatContext>
1638+
template<typename FormatContext, typename Type>
16441639
STRONG_CONSTEXPR
16451640
decltype(auto)
1646-
format(const ::strong::formattable::modifier<type>& t, FormatContext& fc)
1647-
noexcept(noexcept(std::declval<formatter<T, Char>>().format(value_of(std::declval<const type&>()), fc)))
1641+
format(const Type& t, FormatContext& fc)
1642+
noexcept(noexcept(std::declval<formatter<T, Char>>().format(std::declval<const T&>(), fc)))
16481643
{
1649-
const auto& tt = static_cast<const type&>(t);
1650-
return formatter<T, Char>::format(value_of(tt), fc);
1644+
return formatter<T, Char>::format(value_of(t), fc);
16511645
}
16521646
};
16531647
#endif
16541648

16551649
}
16561650

16571651
#if STRONG_HAS_FMT_FORMAT
1658-
namespace fmt
1659-
{
1660-
template<typename T, typename Tag, typename... M, typename Char>
1661-
struct formatter<::strong::type<T, Tag, M...>, Char>
1662-
: std::enable_if_t<
1663-
std::is_base_of<
1664-
::strong::formattable::modifier<
1665-
::strong::type<T, Tag, M...>
1666-
>,
1667-
::strong::type<T, Tag, M...>
1668-
>::value,
1669-
formatter<T>
1670-
>
1652+
namespace strong {
1653+
1654+
template <typename T, typename Char>
1655+
struct formatter;
1656+
1657+
template <typename T, typename Tag, typename ... M, typename Char>
1658+
struct formatter<type<T, Tag, M...>, Char> : fmt::formatter<T, Char>
16711659
{
1672-
using type = ::strong::type<T, Tag, M...>;
1673-
template<typename FormatContext>
1660+
template<typename FormatContext, typename Type>
16741661
STRONG_CONSTEXPR
16751662
decltype(auto)
1676-
format(const ::strong::formattable::modifier<type>& t, FormatContext& fc)
1677-
noexcept(noexcept(std::declval<formatter<T, Char>>().format(value_of(std::declval<const type&>()), fc)))
1663+
format(const Type& t, FormatContext& fc)
1664+
noexcept(noexcept(std::declval<fmt::formatter<T, Char>>().format(std::declval<const T&>(), fc)))
16781665
{
1679-
const auto& tt = static_cast<const type&>(t);
1680-
return formatter<T, Char>::format(value_of(tt), fc);
1666+
return fmt::formatter<T, Char>::format(value_of(t), fc);
16811667
}
16821668
};
1669+
1670+
#if FMT_VERSION >= 90000
1671+
1672+
template <typename T, typename Char, bool = is_formattable<T>::value>
1673+
struct select_formatter;
1674+
1675+
template <typename T, typename Char>
1676+
struct select_formatter<T, Char, true>
1677+
{
1678+
using type = formatter<T, Char>;
1679+
};
1680+
1681+
template <typename T, typename Char>
1682+
struct select_formatter<T, Char, false>
1683+
{
1684+
using type = fmt::ostream_formatter;
1685+
};
1686+
1687+
#endif
1688+
}
1689+
namespace fmt
1690+
{
1691+
#if FMT_VERSION >= 90000
1692+
template <typename T, typename Tag, typename ... M, typename Char>
1693+
struct formatter<::strong::type<T, Tag, M...>,
1694+
Char,
1695+
::strong::impl::void_t<std::enable_if_t<::strong::is_ostreamable<::strong::type<T, Tag, M...>>::value ||
1696+
::strong::is_formattable<::strong::type<T, Tag, M...>>::value>>>
1697+
: ::strong::select_formatter<::strong::type<T, Tag, M...>, Char>::type
1698+
{
1699+
};
1700+
#else
1701+
template<typename T, typename Tag, typename... M, typename Char>
1702+
struct formatter<::strong::type<T, Tag, M...>,
1703+
Char,
1704+
::strong::impl::void_t<std::enable_if_t<::strong::is_formattable<::strong::type<T, Tag, M...>>::value>>
1705+
>
1706+
: ::strong::formatter<::strong::type<T, Tag, M...>, Char>
1707+
{
1708+
};
1709+
#endif
1710+
16831711
}
16841712
#endif
16851713
#endif //ROLLBEAR_STRONG_TYPE_HPP_INCLUDED

0 commit comments

Comments
 (0)