Skip to content

Commit 3f7ceb2

Browse files
committed
Improve std::from_range detection for compilers not defining __cpp_lib_containers_ranges
1 parent 47adc9f commit 3f7ceb2

2 files changed

Lines changed: 31 additions & 15 deletions

File tree

include/boost/container/detail/range_utils.hpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,21 @@
2626
//! Defines boost::container::from_range_t and the boost::container::from_range
2727
//! tag, used to disambiguate the range-based members of the containers.
2828
//!
29-
//! When the standard library provides ::std::from_range_t (feature-test macro
30-
//! __cpp_lib_containers_ranges), from_range_t is a reference to it -following
31-
//! the same technique as boost::container::piecewise_construct_t and
32-
//! boost::container::allocator_arg_t- so the tag is the very same type as the
33-
//! standard one and interoperates with ::std::from_range, yet the heavyweight
34-
//! <ranges> header is not required. Otherwise, there is no standard type to
35-
//! refer to and from_range_t is defined as a standalone type.
29+
//! When the standard library provides ::std::from_range_t (see
30+
//! BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT in std_fwd.hpp), from_range_t
31+
//! is a reference to it -following the same technique as
32+
//! boost::container::piecewise_construct_t and boost::container::allocator_arg_t-
33+
//! so the tag is the very same type as the standard one and interoperates with
34+
//! ::std::from_range, yet the heavyweight <ranges> header is not required.
35+
//! Otherwise, there is no standard type to refer to and from_range_t is defined
36+
//! as a standalone type.
3637

3738
namespace boost {
3839
namespace container {
3940

4041
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
4142

42-
#if defined(__cpp_lib_containers_ranges)
43+
#if defined(BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT)
4344

4445
template <int Dummy = 0>
4546
struct std_from_range_holder
@@ -55,7 +56,7 @@ typedef const ::std::from_range_t & from_range_t;
5556
//! A instance of type from_range_t
5657
static from_range_t from_range = *std_from_range_holder<>::dummy;
5758

58-
#else //!defined(__cpp_lib_containers_ranges)
59+
#else //!defined(BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT)
5960

6061
//The standard library does not provide ::std::from_range_t, so there is nothing
6162
//to interoperate with: from_range_t is a standalone type.
@@ -64,7 +65,7 @@ struct from_range_t {};
6465
//! A instance of type from_range_t
6566
static const from_range_t from_range = from_range_t();
6667

67-
#endif //defined(__cpp_lib_containers_ranges)
68+
#endif //defined(BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT)
6869

6970
#else //BOOST_CONTAINER_DOXYGEN_INVOKED
7071

include/boost/container/detail/std_fwd.hpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@
2525

2626
#include <cstddef>
2727

28-
//<version> is needed to reliably query the __cpp_lib_containers_ranges
29-
//feature-test macro, which tells whether the standard library provides
30-
//::std::from_range_t. It is one of the lightest standard headers (only macros).
28+
//<version> is needed to reliably query the C++23 library feature-test macros
29+
//for ::std::from_range_t / P1206R7. It is one of the lightest standard headers.
3130
#if defined(__has_include)
3231
# if __has_include(<version>)
3332
# include <version>
@@ -36,6 +35,22 @@
3635
# include <version>
3736
#endif
3837

38+
// Whether ::std::from_range_t tag is provided by the standard library.
39+
//
40+
// The official feature-test macro for std::from_range_t is
41+
// __cpp_lib_containers_ranges. However, std::from_range_t lives in <ranges>
42+
// next to std::ranges::to, whose specification uses the tag, so any library
43+
// that provides std::ranges::to necessarily provides std::from_range_t too.
44+
//
45+
// Some standard libraries (e.g. libc++ 17/18) ship std::ranges::to and
46+
// std::from_range_t -- defining __cpp_lib_ranges_to_container -- before they
47+
// complete the container support and define __cpp_lib_containers_ranges.
48+
// In that window only __cpp_lib_ranges_to_container is defined even though the
49+
// tag is already present.
50+
#if defined(__cpp_lib_ranges_to_container) || defined(__cpp_lib_containers_ranges)
51+
# define BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT
52+
#endif
53+
3954
#include <boost/move/detail/std_ns_begin.hpp>
4055
BOOST_MOVE_STD_NS_BEG
4156

@@ -70,8 +85,8 @@ template <class Ptr>
7085
struct pointer_traits;
7186

7287
//Only forward declare ::std::from_range_t when the standard library actually
73-
//provides it; otherwise there is no such type to refer to.
74-
#if defined(__cpp_lib_containers_ranges)
88+
//provides it; see BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT above.
89+
#if defined(BOOST_CONTAINER_DETAIL_STD_FROM_RANGE_SUPPORT)
7590
struct from_range_t;
7691
#endif
7792

0 commit comments

Comments
 (0)