From bb4854fca80cc20f0ebd60bfae2557d7c754073e Mon Sep 17 00:00:00 2001 From: Recolic Keghart <root@recolic.net> Date: Wed, 11 Aug 2021 10:54:18 +0000 Subject: [PATCH] bug fix for rlib::printable_iter, to allow object that only has nonconst begin() to get printable_iter --- require/cxx20 | 12 ++++++++++++ stdio.hpp | 49 +++++++++++++++++++++++++++++----------------- test/src/common.cc | 7 ++++++- 3 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 require/cxx20 diff --git a/require/cxx20 b/require/cxx20 new file mode 100644 index 0000000..8202250 --- /dev/null +++ b/require/cxx20 @@ -0,0 +1,12 @@ +#ifndef R_CXX20_REQUIRED +#define R_CXX20_REQUIRED + +#include <rlib/sys/os.hpp> + +#if RLIB_CXX_STD <= 2017 +#error This file requires compiler and library support \ +for the ISO C++ 2020 standard. This support must be enabled \ +with the -std=c++20 or -std=c++2a compiler options. +#endif + +#endif diff --git a/stdio.hpp b/stdio.hpp index cdc028a..ced54db 100644 --- a/stdio.hpp +++ b/stdio.hpp @@ -102,19 +102,22 @@ namespace rlib { template <typename Iterable, typename Printable> struct _printable_iterable : private std::pair<Iterable, Printable> { using std::pair<Iterable, Printable>::pair; - const Iterable &arg() const {return std::pair<Iterable, Printable>::first;} - const Printable &spliter() const {return std::pair<Iterable, Printable>::second;} + using _printable_iterable_tag = void; + Iterable &arg() & {return std::pair<Iterable, Printable>::first;} + Printable &spliter() & {return std::pair<Iterable, Printable>::second;} + Iterable &&arg() && {return std::pair<Iterable, Printable>::first;} + Printable &&spliter() && {return std::pair<Iterable, Printable>::second;} + const Iterable &arg() const & {return std::pair<Iterable, Printable>::first;} + const Printable &spliter() const & {return std::pair<Iterable, Printable>::second;} }; + template <typename FirstT, typename SecondT> using FirstOf = FirstT; } - // 2 more interfaces... - template <typename Iterable, typename Printable> - const impl::_printable_iterable<Iterable, Printable> printable_iter(Iterable arg, Printable spliter) { - return impl::_printable_iterable<Iterable, Printable>(arg, spliter); - } - template <typename Iterable> - const impl::_printable_iterable<Iterable, char> printable_iter(Iterable arg) { - return impl::_printable_iterable<Iterable, char>(arg, ' '); + // more interfaces... + template <typename Iterable, typename Printable = char> + auto printable_iter(Iterable &&arg, Printable spliter = ' ') -> impl::_printable_iterable<typename std::decay<Iterable>::type, Printable> { + // TODO: avoid the extra copy while passing lvalue reference on constructing return value obj. + return impl::_printable_iterable<typename std::decay<Iterable>::type, Printable>(std::forward<Iterable>(arg), spliter); } inline bool sync_with_stdio(bool sync = true) noexcept { @@ -124,8 +127,8 @@ namespace rlib { return impl::enable_endl_flush() = enable; } -// Implements. - template < class CharT, class Traits > + // Implements below --------------------- + template <typename CharT, typename Traits> inline std::basic_ostream<CharT, Traits>& endl(std::basic_ostream<CharT, Traits>& os) { os << RLIB_IMPL_ENDLINE; if(impl::enable_endl_flush()) @@ -215,12 +218,22 @@ namespace rlib { } } // end namespace rlib -template <typename Iterable, typename Printable> -std::ostream& operator<< (std::ostream& stream, const rlib::impl::_printable_iterable<Iterable, Printable> &p) { - for(auto val : p.arg()) { - stream << val << p.spliter(); - } - return stream; +// auto-deduct const/nonconst left/right value ref. +// For C++20 std::view, it doesn't have a `begin()` method for const lvalue ref. So we have to support +// passing rvalue from rlib::printable_iter() to rlib::impl::_printable_iterable to operator<< +// Instead of writing 3 overloads here, let us deduce automatically. +template <typename PrintableIterableT> +rlib::impl::FirstOf<std::ostream&, typename std::decay<PrintableIterableT>::type::_printable_iterable_tag> operator<< (std::ostream& stream, PrintableIterableT &&p) { + for(auto val : p.arg()) + stream << val << p.spliter(); + return stream; } +// // Old version, for backup +// template <typename Iterable, typename Printable> +// std::ostream& operator<< (std::ostream& stream, rlib::impl::_printable_iterable<Iterable, Printable> &&p) { +// for(auto val : p.arg()) +// stream << val << p.spliter(); +// return stream; +// } #endif diff --git a/test/src/common.cc b/test/src/common.cc index 183c976..946908f 100644 --- a/test/src/common.cc +++ b/test/src/common.cc @@ -82,7 +82,12 @@ TEST_CASE("stdio.hpp") { std::stringstream ss1, ss2; rlib::println(ss1, rlib::printable_iter(v, rlib::printable_iter(v))); rlib::print(ss2, rlib::printable_iter(v, rlib::printable_iter(v))); - rlib::println(ss1.str() == answer + '\n', ss2.str() == answer); + rlib::println(ss1.str() == answer + RLIB_IMPL_ENDLINE, ss2.str() == answer); + + const rlib_test_iterable vc{1.2, 6.666, 12, -11.11}; + std::stringstream ssvc; + rlib::println(ssvc, rlib::printable_iter(vc, rlib::printable_iter(vc))); + REQUIRE(ssvc.str() == answer + RLIB_IMPL_ENDLINE); } -- GitLab