20template <
typename CharT>
26template <
typename CharT>
34constexpr char endl[] =
"\n";
36constexpr char plus[] =
" + ";
40template <
typename T,
typename CharT>
41struct is_writable_stream : std::integral_constant<bool, std::is_same<T, std::basic_ostringstream<CharT>>::value ||
42 std::is_same<T, std::basic_stringstream<CharT>>::value ||
43 std::is_same<T, std::basic_ostream<CharT>>::value> {};
45template <
typename T,
typename CharT =
char>
46struct is_stringstream : std::integral_constant<bool, std::is_same<T, std::basic_istringstream<CharT>>::value ||
47 std::is_same<T, std::basic_ostringstream<CharT>>::value ||
48 std::is_same<T, std::basic_stringstream<CharT>>::value> {};
50template <
typename T,
typename CharT =
char>
51struct is_c_str : std::integral_constant<bool, std::is_same<typename std::decay<T>::type, CharT const*>::value ||
52 std::is_same<typename std::decay<T>::type, CharT*>::value> {};
55struct is_char_sequence
56 : std::integral_constant<bool, is_c_str<T, char>::value || is_c_str<T, wchar_t>::value ||
57 is_c_str<T, char16_t>::value || is_c_str<T, char32_t>::value> {};
61 : std::integral_constant<bool, std::is_same<T, std::string>::value || std::is_same<T, std::wstring>::value ||
62 std::is_same<T, std::u16string>::value ||
63 std::is_same<T, std::u32string>::value> {};
65struct can_const_begin_end_impl {
66 template <typename T, typename B = decltype(std::begin(std::declval<const T&>())),
67 typename E =
decltype(std::end(std::declval<const T&>()))>
68 static std::true_type test(
int);
69 template <
typename...>
70 static std::false_type test(...);
74struct can_const_begin_end :
public decltype(can_const_begin_end_impl::test<T>(0)) {};
77struct is_iterable : std::integral_constant<bool, can_const_begin_end<T>::value && !is_string<T>::value &&
78 !is_stringstream<T>::value && !is_char_sequence<T*>::value> {};
80template <
typename CharT>
81struct does_overload_ostream_impl {
82 template <
typename T,
typename B = decltype(std::declval<std::basic_ostream<CharT>&>() << std::declval<const T&>())>
84 static std::true_type test(
int);
85 template <
typename...>
86 static std::false_type test(...);
89template <
typename CharT,
typename T>
90struct does_overload_ostream :
public decltype(does_overload_ostream_impl<CharT>::template test<T>(0)) {};
92template <
typename CharT,
typename T>
93struct is_parametrized_manipulator
94 : std::integral_constant<
95 bool, std::is_same<T, decltype(std::setbase(std::declval<int>()))>
::value ||
96 std::is_same<T, decltype(std::setprecision(std::declval<int>()))>
::value ||
97 std::is_same<T, decltype(std::setw(std::declval<int>()))>
::value ||
98 std::is_same<T, decltype(std::setfill(std::declval<CharT>()))>
::value ||
99 std::is_same<T, decltype(std::setiosflags(std::declval<std::ios::fmtflags>()))>
::value ||
100 std::is_same<T, decltype(std::resetiosflags(std::declval<std::ios::fmtflags>()))>
::value> {};
102template <
typename CharT,
typename T>
104 : std::integral_constant<bool, (std::is_function<T>::value || is_parametrized_manipulator<CharT, T>::value) &&
105 does_overload_ostream<CharT, T>::value> {};
107template <
typename T,
template <
typename...>
class Template>
108struct is_specialization_of : std::false_type {};
110template <
template <
typename...>
class Template,
typename... Args>
111struct is_specialization_of<Template<Args...>, Template> : std::true_type {};
113template <
bool B,
class T =
void>
114using enable_if_t =
typename std::enable_if<B, T>::type;
119template <
typename CharT,
typename W>
120std::basic_string<CharT> concat_to_string(
const W& writer) {
121 return writer.good() ? writer.str() : std::basic_string<CharT>();
124template <
typename CharT,
char head,
char... tail>
125std::basic_string<CharT> get_separator() {
126 return {head, tail...};
129template <
typename W,
typename S>
130void separate(W& writer,
const S*
separator) {
134template <
typename W,
typename S>
135void separate(W& writer,
const S&
separator) {
139template <
typename CharT,
typename T,
typename W,
typename S>
140void concat_impl_write_separator(W& writer,
const S&
separator) {
141 if (!is_manipulator<CharT, T>::value) separate(writer,
separator);
144template <
typename CharT,
typename W,
typename S,
typename... Args>
145void concat_impl_write_element(W&,
const S&,
const std::tuple<Args...>&);
147template <
typename CharT,
typename W,
typename S,
typename P1,
typename P2>
148void concat_impl_write_element(W&,
const S&,
const std::pair<P1, P2>&);
152template <
typename CharT,
typename W,
typename S,
typename T>
153enable_if_t<!is_iterable<T>::value && !is_stringstream<T>::value,
void> concat_impl_write_element(W& writer,
const S&,
159template <
typename CharT,
typename W,
typename S,
typename T>
160enable_if_t<is_char_sequence<T*>::value,
void> concat_impl_write_element(W& writer,
const S&,
const T* element) {
161 if (element) writer << element;
165template <
typename CharT,
typename W,
typename S,
typename T>
166enable_if_t<is_stringstream<T>::value,
void> concat_impl_write_element(W& writer,
const S&,
const T& element) {
168 writer << concat_to_string<CharT>(element);
170 writer.setstate(element.rdstate());
174template <
typename CharT,
typename W,
typename S,
typename T>
175enable_if_t<is_iterable<T>::value,
void> concat_impl_write_element(W& writer,
const S&
separator,
const T& container) {
176 auto it = std::begin(container), et = std::end(container);
178 concat_impl_write_element<CharT>(writer,
separator, *it);
179 if (++it != et) concat_impl_write_separator<CharT, T>(writer,
separator);
184template <
unsigned N,
unsigned Last>
185struct tuple_printer {
186 template <
typename CharT,
typename W,
typename S,
typename T>
187 static void print(W& writer,
const S&
separator,
const T& tuple) {
188 concat_impl_write_element<CharT>(writer,
separator, std::get<N>(tuple));
189 concat_impl_write_separator<CharT, T>(writer,
separator);
190 tuple_printer<N + 1, Last>::template print<CharT>(writer,
separator, tuple);
195struct tuple_printer<
N,
N> {
196 template <
typename CharT,
typename W,
typename S,
typename T>
197 static void print(W& writer,
const S&
separator,
const T& tuple) {
198 concat_impl_write_element<CharT>(writer,
separator, std::get<N>(tuple));
202template <
typename CharT,
typename W,
typename S,
typename... Args>
203inline void concat_impl_write_element(W& writer,
const S&
separator,
const std::tuple<Args...>& tuple) {
204 tuple_printer<0,
sizeof...(Args) - 1>::template print<CharT>(writer,
separator, tuple);
208template <
typename CharT,
typename W,
typename S,
typename P1,
typename P2>
209inline void concat_impl_write_element(W& writer,
const S&
separator,
const std::pair<P1, P2>& pair) {
210 concat_impl_write_element<CharT>(writer,
separator, pair.first);
211 concat_impl_write_separator<CharT, std::pair<P1, P2>>(writer,
separator);
212 concat_impl_write_element<CharT>(writer,
separator, pair.second);
216template <
typename CharT,
typename W,
typename S,
typename T,
typename... Args>
217void concat_impl_write_element(W& writer,
const S&
separator,
const T& head,
const Args&... tail) {
218 concat_impl_write_element<CharT>(writer,
separator, head);
219 concat_impl_write_separator<CharT, T>(writer,
separator);
220 concat_impl_write_element<CharT>(writer,
separator, tail...);
224template <
typename CharT,
typename S,
typename T,
typename... Args,
225 typename = enable_if_t<is_writable_stream<T, CharT>::value,
T>>
226std::basic_string<CharT> concat_impl(
const S&
separator, T& writer,
const Args&... seq) {
227 concat_impl_write_element<CharT>(writer,
separator, seq...);
228 return concat_to_string<CharT>(writer);
232template <
typename CharT,
typename S,
typename... Args>
233std::basic_string<CharT> concat_impl(
const S&
separator,
const Args&... seq) {
234 std::basic_ostringstream<CharT> writer;
235 return concat_impl<CharT>(
separator, writer, seq...);
241template <
typename CharT = char,
typename... Args>
243 return concat_impl<CharT>(sep.
sep, std::forward<Args>(seq)...);
247template <
char head,
char... tail,
typename F,
typename... Args,
248 typename = enable_if_t<!std::is_same<F, separator_t<char>>
::value, F>>
249std::basic_string<char>
concat(F&& first, Args&&... rest) {
250 return concat_impl<char>(get_separator<char, head, tail...>(), std::forward<F>(first), std::forward<Args>(rest)...);
254template <
const char* sep,
typename F,
typename... Args,
255 typename = enable_if_t<!std::is_same<F, separator_t<char>>
::value, F>>
256std::basic_string<char>
concat(F&& first, Args&&... rest) {
257 return concat_impl<char>(sep, std::forward<F>(first), std::forward<Args>(rest)...);
261template <
typename CharT = char,
typename F,
typename... Args,
262 typename = enable_if_t<!std::is_same<F, separator_t<CharT>>
::value, F>>
263std::basic_string<CharT>
concat(F&& first, Args&&... rest) {
264 return concat_impl<CharT>((
const CharT*)
nullptr, std::forward<F>(first), std::forward<Args>(rest)...);
268template <std::ostream& sep(std::ostream&),
typename CharT = char,
typename F,
typename... Args,
269 typename = enable_if_t<!std::is_same<F, separator_t<CharT>>
::value, F>>
270std::basic_string<CharT>
concat(F&& first, Args&&... rest) {
271 return concat_impl<CharT>(sep, std::forward<F>(first), std::forward<Args>(rest)...);