libstdc++: potential bug in specification of layouts.
Luc Grosheintz
luc.grosheintz@gmail.com
Tue Jun 24 08:59:44 GMT 2025
On 6/23/25 09:43, Tomasz Kaminski wrote:
>
> I have suggested an alternative of providing a non-member operator ==:
> I think that this could be fixed by changing the friend operator== in
> layout_stride,
> to generic overload in std:
> template<typename StridedMapping1, typename StridedMapping2>
> constexpr bool operator==(const StridedMapping1& lhs, const
> StridedMapping2& rhs);
> Constrains:
> ** **layout-mapping-alike*
> <https://en.cppreference.com/w/cpp/named_req/LayoutMapping#layout-mapping-alike>
> <StridedMapping1> && *layout-mapping-alike*
> <https://en.cppreference.com/w/cpp/named_req/LayoutMapping#layout-mapping-alike>
> <StridedMapping12>
> * StridedMapping1::extents_type::rank() ==
> StridedMapping2::extents_type::rank()
> * StridedMapping1::is_always_strided() && StridedMapping2::
> is_always_strided()
> This would allow any strided mapping to be compared without conversions.
> [...]
Thank you, nice suggestion! Though it seems to have the effect of
adding an operator== to certain objects in a way that might be
unintended. I'll explain:
I've implemented the free-standing version:
template<__mdspan::__mapping_alike _SMapping,
__mdspan::__mapping_alike _OMapping>
requires ((_SMapping::extents_type::rank()
== _OMapping::extents_type::rank())
&& _SMapping::is_always_strided()
&& _OMapping::is_always_strided())
constexpr bool
operator==(const _SMapping& __self, const _OMapping& __other)
noexcept
{
// ...
}
and deleted operator== from all three layouts.
Next, I added a class that only structurally resembles a layout
mapping, but semantically isn't supposed to be a mapping at all,
i.e. it's meant to demonstrate some arbitrary user code that just
happens to look like a mapping.
template<typename M1, typename M2>
concept has_op_eq = requires (M1 m1, M2 m2)
{
{ m1 == m2 } -> std::same_as<bool>;
};
// Dummy is only used to play ADL games.
template<typename Dummy>
struct not_a_mapping
{
using extents_type = std::extents<int, 1>;
static constexpr bool
is_always_unique() noexcept { return true; }
static constexpr bool
is_always_exhaustive() noexcept { return true; }
static constexpr bool
is_always_strided() noexcept { return true; }
};
static_assert(std::__mdspan::__mapping_alike<
not_a_mapping<std::array<int, 2>>>);
static_assert(has_op_eq<
not_a_mapping<std::array<int, 2>>,
not_a_mapping<std::array<int, 2>>>);
My concern is that we've now added a comparison operator to two
user-defined classes. This works due to this part of ADL: the
namespace in which template arguments are defined are also
added to the set of associated namespaces. See, second half
of this paragraph:
https://eel.is/c++draft/basic.lookup.argdep#3.2
Potential fix: we could ask that at least one of the two objects
is a standardized mapping.
Next I'll try to break my suggestion as proposed; but that can be
a separate thread.
More information about the Libstdc++
mailing list