cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

request for comments: оператор вывода tuple в поток #571

Closed fukanchik closed 10 months ago

fukanchik commented 10 months ago

Идея: хочется писать std::cout << std::tuple(1,2,"str") << std::endl; или ещё напрмер BOOST_LOG_TRIVIAL(error) << std::tuple(1,2,"str"); или serializer_stream << std::tuple(1,2,"str");

Сложно сказать, будет ли такая штука полезна в стандартной библиотеке. В питоне, например, печатается без проблем, но формат жёсткий - (element,...)

Я не настоящий c++-сник, поэтому у меня получились вот такие две реализации: рекурсивная:

#include <iostream>
#include <string>
#include <tuple>

template <std::size_t N = 0, typename... T>
void foo(std::ostream &os, const std::tuple<T...> &t) {
  if (N != 0)
    os << ",";
  os << std::get<N>(t);
  if constexpr ((N + 1) != sizeof...(T))
    foo<std::size_t(N + 1), T...>(os, t);
}

template <typename... T>
std::ostream &operator<<(std::ostream &os, const std::tuple<T...> &t) {
  foo(os, t);
  return os;
}
template <typename... T>
std::ostream &operator<<(std::ostream &os, const std::tuple<> &t) {
  return os;
}

int main() {
  std::cout << std::tuple(1, 2, "Hello, world") << std::endl;
  std::cout << std::tuple() << std::endl;
  return 0;
}

вторая:

#include <iostream>
#include <string>
#include <tuple>

template <typename... T> struct X {
  std::ostream &_x;
  X(std::ostream &x) : _x(x) {}

  template <typename N> const N &baz(const N &v, const char *sep) {
    _x << sep << v;
    return v;
  }

  template <std::size_t... Is>
  void bar(const std::tuple<T...> &t, std::index_sequence<Is...>) {
    std::tuple<T...> d{baz(std::get<0>(t), ""),
                       baz(std::get<Is + 1>(t), ",")...};
  }
};

template <typename... T>
std::ostream &operator<<(std::ostream &os, const std::tuple<T...> &t) {
  X<T...>(os).bar(t, std::make_index_sequence<sizeof...(T) - 1>{});
  return os;
}
template <typename... T>
std::ostream &operator<<(std::ostream &os, const std::tuple<> &t) {
  return os;
}

int main() {
  std::cout << std::tuple(1, 2, "Hello, world") << std::endl;
  std::cout << std::tuple() << std::endl;
  return 0;
}
  1. насколько это разумные реализации? какие в них ошибки? можно ли проще и оптимальные?
  2. есть ли смысл заносить это в стандарт? в буст? есть ли в ваших проектах такое?
  3. может, это уже предложено, и я просто не смог его найти в https://wg21.link/index.txt?
  4. не понятно в какое место библиотеки это вставлять чтобы не занести зависимость <iostream> в <tuple> или <tuple> в <iostream>

Полезные ссылки:

KindDragon commented 10 months ago

C++23 поддерживает std::format для tuple, pair и прочих≥ Думаю большинству этого будет достаточно https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2286r8.html