Avoid ambiguous overloads of operator= with optional and variant (#8879)

Does not replace #8854 that is a better implementation but currently not
fully compatible with older compilers.

Also loops around the issue with gcc-15, and fixes issue #8827.

See:
  - the CGAL https://github.com/CGAL/cgal/issues/8827,
- and the upstream gcc bug entry
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119859
This commit is contained in:
Sebastien Loriot 2025-05-12 11:58:05 +02:00 committed by GitHub
commit 25d7076791
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 36 additions and 61 deletions

View File

@ -1286,10 +1286,10 @@ struct Output_visitor {
namespace internal {
template < typename D, typename V = std::tuple<>, typename O = std::tuple<> >
template < typename D, bool with_drop, typename V = std::tuple<>, typename O = std::tuple<> >
struct Derivator
{
typedef Derivator<D, V, O> Self;
typedef Derivator<D, with_drop, V, O> Self;
Derivator() = default;
Derivator(const Self&) = default;
Self& operator=(const Self&) = delete;
@ -1298,12 +1298,25 @@ struct Derivator
{}
};
template < typename D, typename V1, typename O1, typename... V, typename... O>
struct Derivator<D, std::tuple<V1, V...>, std::tuple<O1, O...> >
: public Derivator<D, std::tuple<V...>, std::tuple<O...> >
template < typename D>
struct Derivator<D, true, std::tuple<>, std::tuple<>>
{
typedef Derivator<D, std::tuple<V1, V...>, std::tuple<O1, O...> > Self;
typedef Derivator<D, std::tuple<V...>, std::tuple<O...> > Base;
typedef Derivator<D, true, std::tuple<>, std::tuple<>> Self;
Derivator() = default;
Derivator(const Self&) = default;
Self& operator=(const Self&) = delete;
template <class Tuple>
void tuple_dispatch(const Tuple&){}
template <class T>
Self& operator=(const T&) { return *this; } // dropping value
};
template < typename D, bool with_drop, typename V1, typename O1, typename... V, typename... O>
struct Derivator<D, with_drop, std::tuple<V1, V...>, std::tuple<O1, O...> >
: public Derivator<D, with_drop, std::tuple<V...>, std::tuple<O...> >
{
typedef Derivator<D, with_drop, std::tuple<V1, V...>, std::tuple<O1, O...> > Self;
typedef Derivator<D, with_drop, std::tuple<V...>, std::tuple<O...> > Base;
Derivator() = default;
Derivator(const Self&) = default;
@ -1339,12 +1352,12 @@ auto to_tuple(std::tuple<Args...> &t, std::index_sequence<Is...>)
// OutputIterator which accepts several types in *o++= and dispatches,
// wraps several other output iterators, and dispatches accordingly.
template < typename V, typename O >
class Dispatch_output_iterator;
template < typename V, typename O, bool drop_unknown_value_types>
class Dispatch_output_iterator_impl;
template < typename... V, typename... O >
class Dispatch_output_iterator < std::tuple<V...>, std::tuple<O...> >
: private internal::Derivator<Dispatch_output_iterator< std::tuple<V...>, std::tuple<O...> >, std::tuple<V...>, std::tuple<O...> >
template < typename... V, typename... O, bool drop_unknown_value_types>
class Dispatch_output_iterator_impl < std::tuple<V...>, std::tuple<O...>, drop_unknown_value_types>
: private internal::Derivator<Dispatch_output_iterator_impl< std::tuple<V...>, std::tuple<O...>, drop_unknown_value_types >, drop_unknown_value_types, std::tuple<V...>, std::tuple<O...> >
, public std::tuple<O...>
{
static_assert(sizeof...(V) == sizeof...(O),
@ -1352,7 +1365,7 @@ class Dispatch_output_iterator < std::tuple<V...>, std::tuple<O...> >
static const int size = sizeof...(V);
template <typename D, typename V_, typename O_>
template <typename D, bool with_drop, typename V_, typename O_>
friend struct internal::Derivator;
public:
@ -1368,18 +1381,18 @@ public:
private:
typedef Dispatch_output_iterator Self;
typedef internal::Derivator<Self, Value_type_tuple, Iterator_tuple > Base;
typedef Dispatch_output_iterator_impl Self;
typedef internal::Derivator<Self, drop_unknown_value_types, Value_type_tuple, Iterator_tuple > Base;
public:
using Base::operator=;
using Base::tuple_dispatch;
Dispatch_output_iterator(O... o) : std::tuple<O...>(o...) {}
Dispatch_output_iterator_impl(O... o) : std::tuple<O...>(o...) {}
Dispatch_output_iterator(const Dispatch_output_iterator&)=default;
Dispatch_output_iterator_impl(const Dispatch_output_iterator_impl&)=default;
Self& operator=(const Self& s)
{
@ -1424,6 +1437,10 @@ public:
}
};
template<class V, class O>
using Dispatch_output_iterator = Dispatch_output_iterator_impl<V,O,false>;
template < typename... V, typename... O>
Dispatch_output_iterator<std::tuple<V...>, std::tuple<O...> >
dispatch_output(O... o)
@ -1435,50 +1452,8 @@ dispatch_output(O... o)
// Same as Dispatch_output_iterator, but has a dummy *o++= for all other types
// that drops the data (same as Emptyset_iterator).
template < typename V, typename O >
class Dispatch_or_drop_output_iterator;
template < typename... V, typename... O >
class Dispatch_or_drop_output_iterator < std::tuple<V...>, std::tuple<O...> >
: public Dispatch_output_iterator< std::tuple<V...>, std::tuple<O...> >
{
typedef Dispatch_or_drop_output_iterator Self;
typedef Dispatch_output_iterator< std::tuple<V...>, std::tuple<O...> > Base;
template <typename D, typename V_, typename O_>
friend struct internal::Derivator;
public:
Dispatch_or_drop_output_iterator(O... o) : Base(o...) {}
Dispatch_or_drop_output_iterator(const Dispatch_or_drop_output_iterator&)=default;
Dispatch_or_drop_output_iterator& operator=(const Dispatch_or_drop_output_iterator&)=default;
using Base::operator=;
Self& operator*() { return *this; }
Self& operator++() { return *this; }
Self& operator++(int) { return *this; }
template <class T>
Self& operator=(const T&) { return *this; }
template<typename ... T>
Self& operator=(const std::variant< T ... >& t) {
internal::Output_visitor<Self> visitor(this);
std::visit(visitor, t);
return *this;
}
template<typename ... T>
Self& operator=(const std::optional< std::variant< T ... > >& t) {
internal::Output_visitor<Self> visitor(this);
if(t) std::visit(visitor, *t);
return *this;
}
};
template<class V, class O>
using Dispatch_or_drop_output_iterator = Dispatch_output_iterator_impl<V,O,true>;
template < typename... V, typename... O>
inline