Reputation: 6731
I have an use case that can be reduced to:
#include <vector>
#include <ranges>
#include <tuple>
struct TDat
{
double x, y;
template <std::size_t I>
friend double &get(TDat &Dat)
{ if constexpr (I == 0) return Dat.x; else return Dat.y; }
template <std::size_t I>
friend double const &get(TDat const &Dat)
{ if constexpr (I == 0) return Dat.x; else return Dat.y; }
};
namespace std
{
template <>
struct tuple_size<TDat> : integral_constant<size_t, 2u> {};
template <size_t I>
struct tuple_element<I, TDat>
{ using type = double; };
} // std
class TTable
{
private:
std::vector<TDat> DatVec;
public:
auto GetxVec()
{ return std::views::keys(DatVec); }
};
That piece of code does not compile with G++ 10 because TDat
does not model __has_tuple_element<std::ranges::range_value_t<_Vp>, _Nm>
. The problem seems to be that this concept is defined as (https://github.com/gcc-mirror/gcc/blob/fab263ab0fc10ea08409b80afa7e8569438b8d28/libstdc%2B%2B-v3/include/std/ranges#L3318):
namespace __detail
{
template<typename _Tp, size_t _Nm>
concept __has_tuple_element = requires(_Tp __t)
{
typename tuple_size<_Tp>::type;
requires _Nm < tuple_size_v<_Tp>;
typename tuple_element_t<_Nm, _Tp>;
{ std::get<_Nm>(__t) }
-> convertible_to<const tuple_element_t<_Nm, _Tp>&>;
};
}
I believe that, since the call to get
is qualified, the compiler cannot find my get
functions. Is that conclusion correct? If so, is that the intended behaviour? Is it defined behaviour to define my get functions in the std
namespace?
Upvotes: 5
Views: 385
Reputation: 302748
I believe that, since the call to get is qualified, the compiler cannot find my
get
functions. Is that conclusion correct?
Yes.
If so, is that the intended behaviour?
That's the specified behavior at least. [range.elements.view] defines the concept as:
template<class T, size_t N>
concept has-tuple-element = // exposition only
requires(T t) {
typename tuple_size<T>::type;
requires N < tuple_size_v<T>;
typename tuple_element_t<N, T>;
{ get<N>(t) } -> convertible_to<const tuple_element_t<N, T>&>;
};
where all functions calls in the standard library are implicitly fully qualified unless described otherwise [library.contents]/3:
Whenever a name
x
defined in the standard library is mentioned, the namex
is assumed to be fully qualified as::std::x
, unless explicitly described otherwise.
There is no description otherwise here.
However, whether it's intended or not is a different question. And the answer there is also yes. The Library doesn't actually have a "TupleLike" concept yes. Yes, structured bindings exist, but there's no formal specification of that in the Library yet - so until that happens, all the tuple-like algorithms only work for standard library tuple-like things (pair
, array
, tuple
, etc.)
Is it defined behaviour to define my get functions in the std namespace?
No, you may not.
Upvotes: 3