Skip to content

Commit a9baab2

Browse files
Use underlying type for enums in is_signed/is_unsigned.
With clang >= 21, using is_signed/is_unsigned with "small" enums (having an underlying type smaller than an int) results in strong error, after being reported as warnings for years (see #171). Since boost::is_signed/is_unsigned differs explicitly from the std one, and can return "true" for enums (contrary to the std one), keep this boost behavior and implement a special check for enums. This allows in particular boost::lexical_cast to keep working when converting non-scoped enums from int to strings with clang >= 21, see boostorg/lexical_cast#87).
1 parent 085c27f commit a9baab2

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

include/boost/type_traits/is_signed.hpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <boost/type_traits/is_integral.hpp>
1414
#include <boost/type_traits/remove_cv.hpp>
1515
#include <boost/type_traits/is_enum.hpp>
16+
#include <boost/core/underlying_type.hpp>
1617
#include <climits>
1718

1819
namespace boost {
@@ -25,6 +26,18 @@ namespace boost {
2526

2627
namespace detail{
2728

29+
template <class no_cv_t, bool is_enum>
30+
struct is_signed_values_underlying_type
31+
{
32+
typedef no_cv_t underlying_type;
33+
};
34+
35+
template <class no_cv_t>
36+
struct is_signed_values_underlying_type<no_cv_t, true>
37+
{
38+
typedef typename ::boost::underlying_type<no_cv_t>::type underlying_type;
39+
};
40+
2841
template <class T>
2942
struct is_signed_values
3043
{
@@ -34,14 +47,15 @@ struct is_signed_values
3447
// the correct answer.
3548
//
3649
typedef typename remove_cv<T>::type no_cv_t;
37-
static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
38-
static const no_cv_t zero = (static_cast<no_cv_t>(0));
50+
typedef typename is_signed_values_underlying_type<no_cv_t, ::boost::is_enum<T>::value>::underlying_type underlying_type;
51+
52+
static const underlying_type minus_one = (static_cast<underlying_type>(-1));
53+
static const underlying_type zero = (static_cast<underlying_type>(0));
3954
};
4055

4156
template <class T>
4257
struct is_signed_helper
4358
{
44-
typedef typename remove_cv<T>::type no_cv_t;
4559
BOOST_STATIC_CONSTANT(bool, value = (!(::boost::detail::is_signed_values<T>::minus_one > boost::detail::is_signed_values<T>::zero)));
4660
};
4761

include/boost/type_traits/is_unsigned.hpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <boost/type_traits/is_integral.hpp>
1414
#include <boost/type_traits/is_enum.hpp>
1515
#include <boost/type_traits/remove_cv.hpp>
16+
#include <boost/core/underlying_type.hpp>
1617

1718
#include <climits>
1819

@@ -26,6 +27,18 @@ namespace boost {
2627

2728
namespace detail{
2829

30+
template <class no_cv_t, bool is_enum>
31+
struct is_unsigned_values_underlying_type
32+
{
33+
typedef no_cv_t underlying_type;
34+
};
35+
36+
template <class no_cv_t>
37+
struct is_unsigned_values_underlying_type<no_cv_t, true>
38+
{
39+
typedef typename ::boost::underlying_type<no_cv_t>::type underlying_type;
40+
};
41+
2942
template <class T>
3043
struct is_unsigned_values
3144
{
@@ -35,8 +48,10 @@ struct is_unsigned_values
3548
// the correct answer.
3649
//
3750
typedef typename remove_cv<T>::type no_cv_t;
38-
static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
39-
static const no_cv_t zero = (static_cast<no_cv_t>(0));
51+
typedef typename is_unsigned_values_underlying_type<no_cv_t, ::boost::is_enum<T>::value>::underlying_type underlying_type;
52+
53+
static const underlying_type minus_one = (static_cast<underlying_type>(-1));
54+
static const underlying_type zero = (static_cast<underlying_type>(0));
4055
};
4156

4257
template <class T>

0 commit comments

Comments
 (0)