I think this is a Boost bug.
The type requirements here are:
- CopyConstructible or MoveConstructible.
- Destructor upholds the no-throw exception-safety guarantee.
- Complete at the point of variant template instantiation. (See
boost::recursive_wrapper<T>
for a type wrapper that accepts incomplete types to enable recursive variant types.)
as well as:
- EqualityComparable:
variant
is itself EqualityComparable if and only if every one of its bounded types meets the requirements of the concept.
A reference type is copy constructible, is no-throw destructible, complete, and equality comparable. So we're good on all points there. The issue is that the the visitor used in the implementation is:
template <typename T>
bool operator()(const T& rhs_content) const
{
// Since the precondition ensures lhs and rhs types are same, get T...
known_get<const T> getter;
const T& lhs_content = lhs_.apply_visitor(getter);
// ...and compare lhs and rhs contents:
return Comp()(lhs_content, rhs_content);
}
That is, we're using const T
as the known getter. This is fine for non-reference types, but incorrect for reference types, since known_get
asserts if it gets the wrong type:
T& operator()(T& operand) const BOOST_NOEXCEPT
{
return operand;
}
template <typename U>
T& operator()(U& ) const
{
// logical error to be here: see precondition above
BOOST_ASSERT(false);
return ::boost::detail::variant::forced_return<T&>();
}
With int&
, those overloads become:
const int& operator()(const int& ) const;
const int& operator()(int& ) const; [ U = int ]
The second overload is preferred since the type it refers to would be less const-qualified than the non-template overload. That's why you get the assert, and this behavior is clearly incorrect. We should be able to compare references!
The simpler solution would be to drop the const
s from comparer
and simply use:
template <typename T>
bool operator()(T& rhs_content) const
{
known_get<T> getter;
T& lhs_content = lhs_.apply_visitor(getter);
return Comp()(lhs_content, rhs_content);
}
This would work for reference types as well as const
types.