std::ranges::elements_view для пользовательских данных, похожих на кортежи

У меня есть вариант использования, который можно сократить до:

#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>. Проблема, по-видимому, в том, что эта концепция определяется как " rel="nofollow noreferrer">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?


person metalfox    schedule 09.07.2020    source источник


Ответы (1)


Я считаю, что, поскольку вызов get квалифицирован, компилятор не может найти мои get функции. Верен ли этот вывод?

Да.

Если да, то это предполагаемое поведение?

По крайней мере, это указанное поведение. [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:

Всякий раз, когда упоминается имя x, определенное в стандартной библиотеке, предполагается, что имя x полностью определено как ​::​std​::​x, если явно не указано иное.

Другого описания здесь нет.

А вот задумано это или нет - другой вопрос. И ответ там тоже да. В библиотеке на самом деле нет концепции TupleLike, да. Да, структурированные привязки существуют, но в библиотеке пока нет формальной спецификации для этого, поэтому, пока это не произойдет, все кортежеподобные алгоритмы работают только для кортежеподобных элементов стандартной библиотеки (pair, array, tuple и т. д.).

Определено ли поведение для определения моих функций получения в пространстве имен std?

Нет, вы не можете.

person Barry    schedule 09.07.2020
comment
Значит, нет обходного пути, верно? Другими словами, работает ли elements_view только с стандартными классами, подобными кортежам? - person metalfox; 09.07.2020
comment
@metalfox Да, это правильно. На самом деле у нас пока нет настоящего кортежеподобного протокола. - person Barry; 09.07.2020