SFINAEd fixed_variant relational operators (#33)

* updated CI
* SFINAEd fixed_variant's relational operators
* updated docs
* stylistic
* updated release notes
* reformulated to try to make VS 2015/2017 pass
* reverted, tried dropping convertible_to_bool
* reverted, used CWG1558-resistent local impl of mp_valid
* added missing ::type
* used battle-tested Boost type traits
* stylistic
This commit is contained in:
joaquintides
2026-07-16 20:34:06 +02:00
committed by GitHub
parent 3175ae3c91
commit f6aae2880f
4 changed files with 85 additions and 11 deletions
+8 -3
View File
@@ -11,6 +11,7 @@ on:
env: env:
UBSAN_OPTIONS: print_stacktrace=1 UBSAN_OPTIONS: print_stacktrace=1
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs: jobs:
posix: posix:
@@ -175,12 +176,15 @@ jobs:
container: ubuntu:24.04 container: ubuntu:24.04
os: ubuntu-latest os: ubuntu-latest
install: clang-18 install: clang-18
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-13
- toolset: clang - toolset: clang
cxxstd: "11,14,17,20,2b" cxxstd: "11,14,17,20,2b"
os: macos-14 os: macos-14
- toolset: clang
cxxstd: "11,14,17,20,23,2c"
os: macos-15
- toolset: clang
cxxstd: "11,14,17,20,23,2c"
os: macos-26
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
container: container:
@@ -295,3 +299,4 @@ jobs:
run: | run: |
cd ../boost-root cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
+10 -1
View File
@@ -1,7 +1,7 @@
[library Boost.PolyCollection [library Boost.PolyCollection
[quickbook 1.6] [quickbook 1.6]
[authors [López Muñoz, Joaquín M]] [authors [López Muñoz, Joaquín M]]
[copyright 2016-2025 Joaquín M López Muñoz] [copyright 2016-2026 Joaquín M López Muñoz]
[category containers] [category containers]
[id poly_collection] [id poly_collection]
[dirname poly_collection] [dirname poly_collection]
@@ -1204,6 +1204,15 @@ to allow for the definition of container-level `operator<` and related operators
[section Release notes] [section Release notes]
[section Boost 1.92]
* Made [' `variant_collection_value_type_impl`]`<Ts...>`'s relational operators available
only when the corresponding relational operator is available for all `Ts...`, in
accordance with WG21 paper
[@https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2944r3.html P2944R3].
[endsect]
[section Boost 1.88] [section Boost 1.88]
* Added `boost::variant_collection`, a closed polymorphic collection * Added `boost::variant_collection`, a closed polymorphic collection
+12
View File
@@ -1416,6 +1416,8 @@ a pointer to the contained value otherwise.
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br] [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);` [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
[*Constraints:] `std::declval<const Ti&>()==std::declval<const Ti&>()` is a valid expression
convertible to `bool` for all `Ti` in `Ts...`.[br]
[*Returns:] `x.index()==y.index()&&get<I>(x)==get<I>(y)` with `I==x.index()`. [*Returns:] `x.index()==y.index()&&get<I>(x)==get<I>(y)` with `I==x.index()`.
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ne] [#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ne]
@@ -1425,6 +1427,8 @@ a pointer to the contained value otherwise.
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br] [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);` [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
[*Constraints:] `std::declval<const Ti&>()!=std::declval<const Ti&>()` is a valid expression
convertible to `bool` for all `Ti` in `Ts...`.[br]
[*Returns:] `x.index()!=y.index()||get<I>(x)!=get<I>(y)` with `I==x.index()`. [*Returns:] `x.index()!=y.index()||get<I>(x)!=get<I>(y)` with `I==x.index()`.
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_lt] [#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_lt]
@@ -1434,6 +1438,8 @@ a pointer to the contained value otherwise.
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br] [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);` [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
[*Constraints:] `std::declval<const Ti&>()<std::declval<const Ti&>()` is a valid expression
convertible to `bool` for all `Ti` in `Ts...`.[br]
[*Returns:] `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<get<I>(y)` with `I==x.index()`. [*Returns:] `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<get<I>(y)` with `I==x.index()`.
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_gt] [#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_gt]
@@ -1443,6 +1449,8 @@ a pointer to the contained value otherwise.
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br] [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);` [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
[*Constraints:] `std::declval<const Ti&>()>std::declval<const Ti&>()` is a valid expression
convertible to `bool` for all `Ti` in `Ts...`.[br]
[*Returns:] `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>get<I>(y)` with `I==x.index()`. [*Returns:] `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>get<I>(y)` with `I==x.index()`.
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_le] [#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_le]
@@ -1452,6 +1460,8 @@ a pointer to the contained value otherwise.
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br] [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);` [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
[*Constraints:] `std::declval<const Ti&>()<=std::declval<const Ti&>()` is a valid expression
convertible to `bool` for all `Ti` in `Ts...`.[br]
[*Returns:] `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<=get<I>(y)` with `I==x.index()`. [*Returns:] `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<=get<I>(y)` with `I==x.index()`.
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ge] [#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ge]
@@ -1461,6 +1471,8 @@ a pointer to the contained value otherwise.
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br] [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);` [^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
[*Constraints:] `std::declval<const Ti&>()>=std::declval<const Ti&>()` is a valid expression
convertible to `bool` for all `Ti` in `Ts...`.[br]
[*Returns:] `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>=get<I>(y)` with `I==x.index()`. [*Returns:] `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>=get<I>(y)` with `I==x.index()`.
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.visit] [#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.visit]
@@ -1,4 +1,4 @@
/* Copyright 2024-2025 Joaquin M Lopez Munoz. /* Copyright 2024-2026 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
@@ -24,6 +24,12 @@
#include <boost/mp11/utility.hpp> #include <boost/mp11/utility.hpp>
#include <boost/poly_collection/detail/is_equality_comparable.hpp> #include <boost/poly_collection/detail/is_equality_comparable.hpp>
#include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp> #include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
#include <boost/type_traits/has_equal_to.hpp>
#include <boost/type_traits/has_greater.hpp>
#include <boost/type_traits/has_greater_equal.hpp>
#include <boost/type_traits/has_less.hpp>
#include <boost/type_traits/has_less_equal.hpp>
#include <boost/type_traits/has_not_equal_to.hpp>
#include <boost/type_traits/is_constructible.hpp> #include <boost/type_traits/is_constructible.hpp>
#include <cstddef> #include <cstddef>
#include <limits> #include <limits>
@@ -511,7 +517,14 @@ struct eq_
bool operator()(const T& x,const T& y)const{return x==y;} bool operator()(const T& x,const T& y)const{return x==y;}
}; };
template<typename... Ts> template<typename T>
using eq_constraint=has_equal_to<T,T,bool>;
template<
typename... Ts,
typename std::enable_if<
mp11::mp_all<eq_constraint<Ts>...>::value>::type* =nullptr
>
bool operator==( bool operator==(
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y) const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
{ {
@@ -526,7 +539,14 @@ struct neq_
bool operator()(const T& x,const T& y)const{return x!=y;} bool operator()(const T& x,const T& y)const{return x!=y;}
}; };
template<typename... Ts> template<typename T>
using neq_constraint=has_not_equal_to<T,T,bool>;
template<
typename... Ts,
typename std::enable_if<
mp11::mp_all<neq_constraint<Ts>...>::value>::type* =nullptr
>
bool operator!=( bool operator!=(
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y) const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
{ {
@@ -542,7 +562,14 @@ struct lt_
bool operator()(const T& x,const T& y)const{return x<y;} bool operator()(const T& x,const T& y)const{return x<y;}
}; };
template<typename... Ts> template<typename T>
using lt_constraint=has_less<T,T,bool>;
template<
typename... Ts,
typename std::enable_if<
mp11::mp_all<lt_constraint<Ts>...>::value>::type* =nullptr
>
bool operator<( bool operator<(
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y) const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
{ {
@@ -558,7 +585,14 @@ struct lte_
bool operator()(const T& x,const T& y)const{return x<=y;} bool operator()(const T& x,const T& y)const{return x<=y;}
}; };
template<typename... Ts> template<typename T>
using lte_constraint=has_less_equal<T,T,bool>;
template<
typename... Ts,
typename std::enable_if<
mp11::mp_all<lte_constraint<Ts>...>::value>::type* =nullptr
>
bool operator<=( bool operator<=(
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y) const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
{ {
@@ -574,7 +608,14 @@ struct gt_
bool operator()(const T& x,const T& y)const{return x>y;} bool operator()(const T& x,const T& y)const{return x>y;}
}; };
template<typename... Ts> template<typename T>
using gt_constraint=has_greater<T,T,bool>;
template<
typename... Ts,
typename std::enable_if<
mp11::mp_all<gt_constraint<Ts>...>::value>::type* =nullptr
>
bool operator>( bool operator>(
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y) const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
{ {
@@ -590,7 +631,14 @@ struct gte_
bool operator()(const T& x,const T& y)const{return x>=y;} bool operator()(const T& x,const T& y)const{return x>=y;}
}; };
template<typename... Ts> template<typename T>
using gte_constraint=has_greater_equal<T,T,bool>;
template<
typename... Ts,
typename std::enable_if<
mp11::mp_all<gte_constraint<Ts>...>::value>::type* =nullptr
>
bool operator>=( bool operator>=(
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y) const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
{ {