std::ranges::elements_view 用于自定义类似元组的数据
std::ranges::elements_view for custom tuple-like data
我有一个可以简化为的用例:
#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); }
};
那段代码不能用 G++ 10 编译,因为 TDat
没有建模 __has_tuple_element<std::ranges::range_value_t<_Vp>, _Nm>
。问题似乎是这个概念被定义为 (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>&>;
};
}
我认为,由于对 get
的调用是合格的,编译器无法找到我的 get
函数。这个结论对吗?如果是这样,那是预期的行为吗?在 std
命名空间中定义我的 get 函数是否定义了行为?
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?
这至少是指定的行为。 [range.elements.view]定义概念为:
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>&>;
};
除非另有说明,否则标准库中的所有函数调用都是隐式完全限定的 [library.contents]/3:
Whenever a name x
defined in the standard library is mentioned, the name x
is assumed to be fully qualified as ::std::x
, unless explicitly described otherwise.
这里没有其他说明。
但是,是否有意为之是另一回事。答案也是肯定的。是的,图书馆实际上没有“TupleLike”概念。是的,存在结构化绑定,但库中还没有正式的规范 - 所以在此之前,所有类似元组的算法仅适用于标准库类似元组的东西(pair
,array
, tuple
, 等等)
Is it defined behaviour to define my get functions in the std namespace?
不,你可能不会。
我有一个可以简化为的用例:
#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); }
};
那段代码不能用 G++ 10 编译,因为 TDat
没有建模 __has_tuple_element<std::ranges::range_value_t<_Vp>, _Nm>
。问题似乎是这个概念被定义为 (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>&>;
};
}
我认为,由于对 get
的调用是合格的,编译器无法找到我的 get
函数。这个结论对吗?如果是这样,那是预期的行为吗?在 std
命名空间中定义我的 get 函数是否定义了行为?
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?
这至少是指定的行为。 [range.elements.view]定义概念为:
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>&>;
};
除非另有说明,否则标准库中的所有函数调用都是隐式完全限定的 [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.
这里没有其他说明。
但是,是否有意为之是另一回事。答案也是肯定的。是的,图书馆实际上没有“TupleLike”概念。是的,存在结构化绑定,但库中还没有正式的规范 - 所以在此之前,所有类似元组的算法仅适用于标准库类似元组的东西(pair
,array
, tuple
, 等等)
Is it defined behaviour to define my get functions in the std namespace?
不,你可能不会。