Ok. here's my second attempt.
It has 2 improvements:
1. allows appending to an existing string by specifiying std::string&
join(onto(s), [optional separator("xxx"), parts...);
2. replaces use of std::ostringstream with a (very simple!) version that
does string appending.
#include <sstream>
#include <iostream>
#include <iomanip>
struct string_ref_buffer
: std::streambuf
{
using inherited = std::streambuf;
using char_type = inherited::char_type;
using char_traits = std::char_traits;
int overflow(int c) override
{
if (c != char_traits::eof()) {
buffer_.push_back(c);
}
return char_traits::not_eof(c);
}
string_ref_buffer(std::string& buffer)
: buffer_(buffer)
{
}
const std::string& str() const & { return buffer_; }
std::string&& str()&& { return std::move(buffer_); }
std::string& buffer_;
std::size_t inpos_ = 0;
std::size_t outpos_ = 0;
};
namespace detail {
template<class SepStr>
struct separator_object
{
template<class T>
std::ostream& operator ()(std::ostream& s, T&& t) const
{
return s << sep << t;
}
//
// other iomanp specialisations here
//
std::ostream& operator ()(std::ostream& s,
std::ios_base&(*t)(std::ios_base&)) const
{
t(s);
return s;
}
SepStr const& sep;
};
struct no_separator_object
{
template<class T>
std::ostream& operator ()(std::ostream& s, T&& t) const
{
return s << t;
}
};
template
auto& join_onto(Target&& target, Separator&& sep, Rest&&...rest)
{
string_ref_buffer sbuf { target.str() };
std::ostream ss(std::addressof(sbuf));
using expand = int [];
void(expand{0,
((sep(ss, rest)), 0)...
});
return target;
};
template
auto join(Separator&& sep, String&& s, Rest&&...rest)
{
std::string result {};
string_ref_buffer sbuf { result };
std::ostream ss(std::addressof(sbuf));
ss << s;
using expand = int [];
void(expand{0,
((sep(ss, rest)), 0)...
});
return result;
};
template<class String>
struct onto_type
{
String& str() { return target_.get(); }
std::reference_wrapper<String> target_;
};
}
template<class String>
auto onto(String& target)
{
return detail::onto_type<String> { target };
}
template<class Sep>
static constexpr auto separator(Sep const& sep)
{
using sep_type = std::remove_const_t;
return detail::separator_object { sep };
}
template
decltype(auto) join(detail::separator_object<SepObject> sep, String&&
s, Rest&&...rest)
{
return detail::join(sep,
std::forward<String>(s),
std::forward<Rest>(rest)...);
};
template
decltype(auto) join(String&& s, Rest&&...rest)
{
return detail::join(detail::no_separator_object(),
std::forward<String>(s),
std::forward<Rest>(rest)...);
};
template
decltype(auto) join(detail::onto_type<Target> target,
detail::separator_object<SepObject> sep, String&& s, Rest&&...rest)
{
return detail::join_onto(target,
sep,
std::forward<String>(s),
std::forward<Rest>(rest)...);
};
template
decltype(auto) join(detail::onto_type<Target> target, String&& s, Rest&&...rest)
{
return detail::join_onto(target,
detail::no_separator_object(),
std::forward<String>(s),
std::forward<Rest>(rest)...);
};
int main()
{
auto s= std::string("foo");
s = join("Hello ", ", World.", " The hex for ", 58, " is ", std::hex, 58);
std::cout << s << std::endl;
s = join(separator(" : "), "a", "b", std::hex, 200 , std::quoted("banana"));
std::cout << s << std::endl;
join(onto(s), separator(", "), "funky", "chicken");
join(onto(s), "=====");
std::cout << s << std::endl;
}
expected output:
Hello , World. The hex for 58 is 3a
a : b : c8 : "banana"
a : b : c8 : "banana", funky, chicken=====
On 18 January 2017 at 09:53, Richard Hodges wrote:
That's pretty straightforward with another overload:
auto& s = join(to(y), separator(", "), "A", "b", 42);
where to(y) is something like
template<String>
struct to_existing_type<String> {
String& get() { return s_; }
String s_;
};
template<class String>
auto to(String& s)
{
return to_existing_type<S>(s);
}
With a bit of template unwrapping, we could imagine something like this:
join(to(x), 2, 3, to(y), "foo", "bar", create(), "baz", 42);
which would return a tuple:
std::tuple
in c++17 this would allow:
auto&& [x, y, z] = join(to(x), 2, 3, to(y), "foo", "bar", create(), "baz",
42);
But this maybe taking it a bit far... What do you think?
On 18 January 2017 at 09:06, Olaf van der Spek wrote:
On Mon, Jan 16, 2017 at 11:41 AM, Richard Hodges
wrote:
Sorry to chime in so late in the discussion.
What about a syntax similar to this?
int main()
{
auto s = join("Hello ", ", World.", " The hex for ", 58, " is ",
std::hex, 58);
std::cout << s << std::endl;
s = join(separator(" : "), "a", "b", std::hex, 200 ,
std::quoted("banana"));
std::cout << s << std::endl;
}
Which would produce the following output:
Hello , World. The hex for 58 is 3a
a : b : c8 : “banana"
The syntax is fine but it's missing an appending variant, like append(s,
"A", "B", 42);
This variant is important as it (also) allows you to reuse existing
storage.
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman
/listinfo.cgi/boost