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”概念。是的,存在结构化绑定,但库中还没有正式的规范 - 所以在此之前,所有类似元组的算法仅适用于标准库类似元组的东西(pairarray , tuple, 等等)

Is it defined behaviour to define my get functions in the std namespace?

不,你可能不会。